2 // Copyright (c) 2003, 2004, 2005 Rodrigo B. de Oliveira (rbo@acm.org)
3 // All rights reserved.
5 // Redistribution and use in source and binary forms, with or without modification,
6 // are permitted provided that the following conditions are met:
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and/or other materials provided with the distribution.
13 // * Neither the name of Rodrigo B. de Oliveira nor the names of its
14 // contributors may be used to endorse or promote products derived from this
15 // software without specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 namespace Boo
.Microsoft
.Build
.Tasks
31 import Microsoft
.Build
.Framework
32 import Microsoft
.Build
.Tasks
33 import Microsoft
.Build
.Utilities
35 import System
.Diagnostics
37 import System
.Globalization
38 import System
.Text
.RegularExpressions
39 import System
.Threading
41 class Booc(ManagedCompiler
):
43 Represents the Boo compiler MSBuild task.
46 Sorin Ionescu (sorin.ionescu@gmail.com)
53 Gets/sets a specific pipeline to add to the compiler process.
56 return Bag
['Pipelines'] as string
58 Bag
['Pipelines'] = value
61 Gets/sets if we want to link to the standard libraries or not.
64 return GetBoolParameterWithDefault("NoStandardLib", false)
66 Bag
['NoStandardLib'] = value
69 Gets/sets if we want to use whitespace agnostic mode.
72 return GetBoolParameterWithDefault("WhiteSpaceAgnostic", false)
74 Bag
['WhiteSpaceAgnostic'] = value
77 Gets/sets if we want to use ducky mode.
80 return GetBoolParameterWithDefault("Ducky", false)
85 Gets/sets the verbosity level.
88 return Bag
['Verbosity'] as string
90 Bag
['Verbosity'] = value
94 Gets/sets the culture.
97 return Bag
['Culture'] as string
99 Bag
['Culture'] = value
103 Gets/sets the source directory.
106 return Bag
['Source Directory'] as string
108 Bag
['Source Directory'] = value
112 Gets/sets the conditional compilation symbols.
115 return Bag
['DefineSymbols'] as string
117 Bag
['DefineSymbols'] = value
126 override def Execute():
131 true if the task completed successfully; otherwise, false.
133 boocCommandLine
= CommandLineBuilderExtension()
134 AddResponseFileCommands(boocCommandLine
)
136 warningPattern
= regex(
137 '^(?<file>.*?)(\\((?<line>\\d+),(?<column>\\d+)\\):)?' +
138 '(\\s?)(?<code>BCW\\d{4}):(\\s)WARNING:(\\s)(?<message>.*)$',
139 RegexOptions
.Compiled
)
140 # Captures the file, line, column, code, and message from a BOO warning
141 # in the form of: Program.boo(1,1): BCW0000: WARNING: This is a warning.
143 errorPattern
= regex(
144 '^(((?<file>.*?)\\((?<line>\\d+),(?<column>\\d+)\\): )?' +
145 '(?<code>BCE\\d{4})|(?<errorType>Fatal) error):' +
146 '( Boo.Lang.Compiler.CompilerError:)?' +
147 ' (?<message>.*?)($| --->)',
148 RegexOptions
.Compiled |
149 RegexOptions
.ExplicitCapture |
150 RegexOptions
.Multiline
)
152 * Captures the file, line, column, code, error type, and message from a
153 * BOO error of the form of:
154 * 1. Program.boo(1,1): BCE0000: This is an error.
155 * 2. Program.boo(1,1): BCE0000: Boo.Lang.Compiler.CompilerError:
156 * This is an error. ---> Program.boo:4:19: This is an error
157 * 3. BCE0000: This is an error.
158 * 4. Fatal error: This is an error.
160 * The second line of the following error format is not cought because
161 * .NET does not support if|then|else in regular expressions,
162 * and the regex will be horrible complicated.
163 * The second line is as worthless as the first line.
164 * Therefore, it is not worth implementing it.
166 * Fatal error: This is an error.
167 * Parameter name: format.
171 outputLine
= String
.Empty
172 errorLine
= String
.Empty
173 readingDoneEvents
= (ManualResetEvent(false), ManualResetEvent(false))
175 boocProcessStartInfo
= ProcessStartInfo(
176 FileName
: GenerateFullPathToTool(),
177 Arguments
: boocCommandLine
.ToString(),
179 CreateNoWindow
: true,
180 RedirectStandardError
: true,
181 RedirectStandardInput
: false,
182 RedirectStandardOutput
: true,
183 UseShellExecute
: false)
185 boocProcess
= Process(StartInfo
: boocProcessStartInfo
)
187 parseOutput
= def(line
as string
):
188 warningPatternMatch
= warningPattern
.Match(line
)
189 errorPatternMatch
= errorPattern
.Match(line
)
191 if warningPatternMatch
.Success
:
194 int
.TryParse(warningPatternMatch
.Groups
['line'].Value
, lineOut
)
195 int
.TryParse(warningPatternMatch
.Groups
['column'].Value
, columnOut
)
198 warningPatternMatch
.Groups
['code'].Value
,
200 warningPatternMatch
.Groups
['file'].Value
,
205 warningPatternMatch
.Groups
['message'].Value
)
207 elif errorPatternMatch
.Success
:
208 code
= errorPatternMatch
.Groups
['code'].Value
209 code
= 'BCE0000' if string
.IsNullOrEmpty(code
)
210 file
= errorPatternMatch
.Groups
['file'].Value
211 file
= 'BOOC' if string
.IsNullOrEmpty(file
)
214 lineNumber
= int
.Parse(
215 errorPatternMatch
.Groups
['line'].Value
,
216 NumberStyles
.Integer
)
218 except FormatException
:
222 columnNumber
= int
.Parse(
223 errorPatternMatch
.Groups
['column'].Value
,
224 NumberStyles
.Integer
)
226 except FormatException
:
230 errorPatternMatch
.Groups
['errorType'].Value
.ToLower(),
238 errorPatternMatch
.Groups
['message'].Value
)
243 Log
.LogMessage(MessageImportance
.Normal
, line
)
245 readStandardOutput
= def():
247 outputLine
= boocProcess
.StandardOutput
.ReadLine()
250 parseOutput(outputLine
)
253 readingDoneEvents
[0].Set()
256 readStandardError
= def():
258 errorLine
= boocProcess
.StandardError
.ReadLine()
261 parseOutput(errorLine
)
264 readingDoneEvents
[1].Set()
267 standardOutputReadingThread
= Thread(readStandardOutput
as ThreadStart
)
268 standardErrorReadingThread
= Thread(readStandardError
as ThreadStart
)
269 # Two threads are required (MSDN); otherwise, a deadlock WILL occur.
275 MessageImportance
.High
,
276 "${ToolName} ${boocProcess.StartInfo.Arguments}",
279 standardOutputReadingThread
.Start()
280 standardErrorReadingThread
.Start()
282 WaitHandle
.WaitAny((readingDoneEvents
[0],))
283 WaitHandle
.WaitAny((readingDoneEvents
[1],))
284 # MSBuild runs on an STA thread, and WaitHandle.WaitAll()
287 except e
as Exception
:
288 Log
.LogErrorFromException(e
)
296 protected override def AddCommandLineCommands(
297 commandLine
as CommandLineBuilderExtension
):
299 Adds command line commands.
302 It prevents <ManagedCompiler> from adding the standard commands.
306 protected override def AddResponseFileCommands(
307 commandLine
as CommandLineBuilderExtension
):
309 Generates the Boo compiler command line.
312 The Boo compiler command line.
314 commandLine
.AppendSwitchIfNotNull('-t:', TargetType
)
315 commandLine
.AppendSwitchIfNotNull('-o:', OutputAssembly
)
316 commandLine
.AppendSwitchIfNotNull('-c:', Culture
)
317 commandLine
.AppendSwitchIfNotNull('-srcdir:', SourceDirectory
)
318 commandLine
.AppendSwitchIfNotNull('-keyfile:', KeyFile
)
319 commandLine
.AppendSwitchIfNotNull('-keycontainer:', KeyContainer
)
320 commandLine
.AppendSwitchIfNotNull('-p:', Pipeline
)
321 commandLine
.AppendSwitchIfNotNull('-define:', DefineSymbols
)
322 commandLine
.AppendSwitchIfNotNull("-lib:", AdditionalLibPaths
, ",")
325 commandLine
.AppendSwitch('-nologo')
327 commandLine
.AppendSwitch('-noconfig')
329 commandLine
.AppendSwitch('-nostdlib')
331 commandLine
.AppendSwitch('-delaysign')
332 if WhiteSpaceAgnostic
:
333 commandLine
.AppendSwitch('-wsa')
335 commandLine
.AppendSwitch('-ducky')
337 if EmitDebugInformation
:
338 commandLine
.AppendSwitch('-debug')
340 commandLine
.AppendSwitch('-debug-')
343 for rsp
in ResponseFiles
:
344 commandLine
.AppendSwitchIfNotNull("@", rsp
.ItemSpec
)
347 for reference
in References
:
348 commandLine
.AppendSwitchIfNotNull('-r:', reference
.ItemSpec
)
351 for resource
in Resources
:
352 commandLine
.AppendSwitchIfNotNull('-resource:', resource
.ItemSpec
)
358 StringComparison
.InvariantCultureIgnoreCase
) == 0:
364 StringComparison
.InvariantCultureIgnoreCase
) == 0:
366 commandLine
.AppendSwitch('-v')
371 StringComparison
.InvariantCultureIgnoreCase
) == 0:
373 commandLine
.AppendSwitch('-vv')
378 StringComparison
.InvariantCultureIgnoreCase
) == 0:
380 commandLine
.AppendSwitch('-vvv')
383 Log
.LogErrorWithCodeFromResources(
384 'Vbc.EnumParameterHasInvalidValue',
387 'Normal, Warning, Info, Verbose')
389 commandLine
.AppendFileNamesIfNotNull(Sources
, ' ')
391 protected override def GenerateFullPathToTool():
393 Generats the full path to booc.exe.
398 path
= Path
.Combine(ToolPath
, ToolName
)
400 return path
if File
.Exists(path
)
403 Path
.GetDirectoryName(typeof(Booc
).Assembly
.Location
),
406 return path
if File
.Exists(path
)
408 path
= ToolLocationHelper
.GetPathToDotNetFrameworkFile(
410 TargetDotNetFrameworkVersion
.VersionLatest
)
412 return path
if File
.Exists(path
)
414 /* //removed this error message for mono compatibility
415 Log.LogErrorWithCodeFromResources(
416 "General.FrameworksFileNotFound",
418 ToolLocationHelper.GetDotNetFrameworkVersionFolderPrefix(
419 TargetDotNetFrameworkVersion.Version20))