diff options
author | Lluis Sanchez <lluis@xamarin.com> | 2016-03-01 12:06:10 +0300 |
---|---|---|
committer | Lluis Sanchez <lluis@xamarin.com> | 2016-03-01 17:38:07 +0300 |
commit | 2ec4446e7f4491d13723d1648f70e008e858131d (patch) | |
tree | 7b37ac8105207885e041dfc86357f6dbda67f1f1 /main/src/core/MonoDevelop.Projects.Formats.MSBuild | |
parent | 78e0ff336e0c12e00a18182eb461e07d8f10e6b9 (diff) |
Fix serialization issues in BinaryMessage and related classes
Changed the way dictionaries are serialized. Now dictionaries of any
type are supported, not only <string,object>. Also arrays of any type
are supported.
Improved exception catching and logging.
Diffstat (limited to 'main/src/core/MonoDevelop.Projects.Formats.MSBuild')
12 files changed, 1200 insertions, 0 deletions
diff --git a/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/BuildEngine.Shared.cs b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/BuildEngine.Shared.cs new file mode 100644 index 0000000000..5a55c5cbb2 --- /dev/null +++ b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/BuildEngine.Shared.cs @@ -0,0 +1,320 @@ +// +// ProjectBuilder.cs +// +// Author: +// Lluis Sanchez Gual <lluis@novell.com> +// +// Copyright (c) 2010 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Threading; +using System.Runtime.Remoting; +using System.Collections.Generic; +using System.Globalization; +using System.IO; + +//this is the builder for the deprecated build engine API +using MonoDevelop.Core.Execution; +using System.Net.Configuration; +using System.Diagnostics; +#pragma warning disable 618 + +namespace MonoDevelop.Projects.MSBuild +{ + partial class BuildEngine + { + static readonly AutoResetEvent workDoneEvent = new AutoResetEvent (false); + static ThreadStart workDelegate; + static readonly object workLock = new object (); + static Thread workThread; + static Exception workError; + + static List<int> cancelledTasks = new List<int> (); + static int currentTaskId; + static int projectIdCounter; + Dictionary<int, ProjectBuilder> projects = new Dictionary<int, ProjectBuilder> (); + + readonly ManualResetEvent doneEvent = new ManualResetEvent (false); + + static RemoteProcessServer server; + + internal WaitHandle WaitHandle { + get { return doneEvent; } + } + + public class LogWriter: ILogWriter + { + int id; + + public LogWriter (int loggerId) + { + this.id = loggerId; + } + + public void Write (string text) + { + server.SendMessage (new LogMessage { LoggerId = id, Text = text }); + } + } + + public class NullLogWriter: ILogWriter + { + public void Write (string text) + { + } + } + + void WatchProcess (int procId) + { + var t = new Thread (delegate () { + while (true) { + Thread.Sleep (1000); + try { + // Throws exception if process is not running. + // When watching a .NET process from Mono, GetProcessById may + // return the process with HasExited=true + Process p = Process.GetProcessById (procId); + if (p.HasExited) + break; + } + catch { + break; + } + } + doneEvent.Set (); + }); + t.IsBackground = true; + t.Start (); + } + + public BuildEngine (RemoteProcessServer pserver) + { + server = pserver; + } + + [MessageHandler] + public BinaryMessage Initialize (InitializeRequest msg) + { + WatchProcess (msg.IdeProcessId); + SetCulture (CultureInfo.GetCultureInfo (msg.CultureName)); + SetGlobalProperties (msg.GlobalProperties); + return msg.CreateResponse (); + } + + [MessageHandler] + public LoadProjectResponse LoadProject (LoadProjectRequest msg) + { + var pb = LoadProject (msg.ProjectFile); + lock (projects) { + var id = ++projectIdCounter; + projects [id] = pb; + return new LoadProjectResponse { ProjectId = id }; + } + } + + [MessageHandler] + public BinaryMessage UnloadProject (UnloadProjectRequest msg) + { + ProjectBuilder pb = null; + lock (projects) { + if (projects.TryGetValue (msg.ProjectId, out pb)) + projects.Remove (msg.ProjectId); + } + if (pb != null) + UnloadProject (pb); + return msg.CreateResponse (); + } + + [MessageHandler] + public BinaryMessage Dispose (DisposeRequest msg) + { + doneEvent.Set (); + return msg.CreateResponse (); + } + + [MessageHandler] + public BinaryMessage Ping (PingRequest msg) + { + return msg.CreateResponse (); + } + + [MessageHandler] + public BinaryMessage CancelTask (CancelTaskRequest msg) + { + lock (cancelledTasks) { + if (currentTaskId == msg.TaskId) + AbortCurrentTask (); + else + cancelledTasks.Add (msg.TaskId); + } + return msg.CreateResponse (); + } + + [MessageHandler] + public BinaryMessage SetGlobalProperties (SetGlobalPropertiesRequest msg) + { + SetGlobalProperties (msg.Properties); + return msg.CreateResponse (); + } + + [MessageHandler] + public BinaryMessage DisposeProject (DisposeProjectRequest msg) + { + var pb = GetProject (msg.ProjectId); + if (pb != null) + pb.Dispose (); + return msg.CreateResponse (); + } + + [MessageHandler] + public BinaryMessage RefreshProject (RefreshProjectRequest msg) + { + var pb = GetProject (msg.ProjectId); + if (pb != null) + pb.Refresh (); + return msg.CreateResponse (); + } + + [MessageHandler] + public BinaryMessage RefreshWithContent (RefreshWithContentRequest msg) + { + var pb = GetProject (msg.ProjectId); + if (pb != null) + pb.RefreshWithContent (msg.Content); + return msg.CreateResponse (); + } + + [MessageHandler] + public BinaryMessage RunProject (RunProjectRequest msg) + { + var pb = GetProject (msg.ProjectId); + if (pb != null) { + var logger = msg.LogWriterId != -1 ? (ILogWriter) new LogWriter (msg.LogWriterId) : (ILogWriter) new NullLogWriter (); + var res = pb.Run (msg.Configurations, logger, msg.Verbosity, msg.RunTargets, msg.EvaluateItems, msg.EvaluateProperties, msg.GlobalProperties, msg.TaskId); + return new RunProjectResponse { Result = res }; + } + return msg.CreateResponse (); + } + + ProjectBuilder GetProject (int projectId) + { + lock (projects) { + ProjectBuilder pb; + if (projects.TryGetValue (projectId, out pb)) + return pb; + return null; + } + } + + static bool IsTaskCancelled (int taskId) + { + lock (cancelledTasks) { + return cancelledTasks.Contains (taskId); + } + } + + static bool SetCurrentTask (int taskId) + { + lock (cancelledTasks) { + if (cancelledTasks.Contains (taskId)) + return false; + currentTaskId = taskId; + return true; + } + } + + static void ResetCurrentTask () + { + lock (cancelledTasks) { + currentTaskId = -1; + } + } + + static void AbortCurrentTask () + { + workThread.Abort (); + workThread = null; + workDoneEvent.Set (); + } + + internal static void RunSTA (ThreadStart ts) + { + RunSTA (-1, ts); + } + + internal static void RunSTA (int taskId, ThreadStart ts) + { + lock (workLock) { + if (IsTaskCancelled (taskId)) + return; + lock (threadLock) { + // Last chance to check for canceled task before the thread is started + if (IsTaskCancelled (taskId)) + return; + + workDelegate = ts; + workError = null; + if (workThread == null) { + workThread = new Thread (STARunner); + workThread.SetApartmentState (ApartmentState.STA); + workThread.IsBackground = true; + workThread.CurrentUICulture = uiCulture; + workThread.Start (); + } + else + // Awaken the existing thread + Monitor.Pulse (threadLock); + } + if (!SetCurrentTask (taskId)) { + // The task was aborted after all. Since the thread is already running we need to abort it + AbortCurrentTask (); + return; + } + + workDoneEvent.WaitOne (); + + ResetCurrentTask (); + } + if (workError != null) + throw new Exception ("MSBuild operation failed", workError); + } + + static readonly object threadLock = new object (); + + static void STARunner () + { + lock (threadLock) { + do { + try { + workDelegate (); + } + catch (Exception ex) { + workError = ex; + } + workDoneEvent.Set (); + } + while (Monitor.Wait (threadLock, 60000)); + + workThread = null; + } + } + } +}
\ No newline at end of file diff --git a/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/IBuildEngine.cs b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/IBuildEngine.cs new file mode 100644 index 0000000000..b3ef0b3c21 --- /dev/null +++ b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/IBuildEngine.cs @@ -0,0 +1,43 @@ +// +// IProjectBuilder.cs +// +// Author: +// Lluis Sanchez Gual <lluis@novell.com> +// +// Copyright (c) 2010 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Globalization; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace MonoDevelop.Projects.MSBuild +{ + public interface IBuildEngine: IDisposable + { + Task SetCulture (CultureInfo uiCulture); + Task SetGlobalProperties (IDictionary<string, string> properties); + Task<IProjectBuilder> LoadProject (string projectFile); + Task UnloadProject (IProjectBuilder pb); + Task Ping (); + Task CancelTask (int taskId); + } +} diff --git a/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/ILogWriter.cs b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/ILogWriter.cs new file mode 100644 index 0000000000..6e8ec1225b --- /dev/null +++ b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/ILogWriter.cs @@ -0,0 +1,57 @@ +// +// ILogWriter.cs +// +// Author: +// Lluis Sanchez Gual <lluis@novell.com> +// +// Copyright (c) 2009 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.IO; +using System.Runtime.Remoting.Messaging; + +namespace MonoDevelop.Projects.MSBuild +{ + public interface ILogWriter + { + void Write (string text); + } + + public class LogWriter: MarshalByRefObject, ILogWriter + { + TextWriter writer; + + public LogWriter (TextWriter writer) + { + this.writer = writer; + } + + public void Write (string text) + { + writer.Write (text); + } + + public override object InitializeLifetimeService () + { + return null; + } + } +} diff --git a/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/IProjectBuilder.cs b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/IProjectBuilder.cs new file mode 100644 index 0000000000..8acbb5aa63 --- /dev/null +++ b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/IProjectBuilder.cs @@ -0,0 +1,44 @@ +// +// IProjectBuilder.cs +// +// Author: +// Lluis Sanchez Gual <lluis@novell.com> +// Michael Hutchinson <m.j.hutchinson@gmail.com> +// +// Copyright (c) 2009-2011 Novell, Inc (http://www.novell.com) +// Copyright (c) 2011-2015 Xamarin Inc. (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace MonoDevelop.Projects.MSBuild +{ + public interface IProjectBuilder : IDisposable + { + Task Refresh (); + Task RefreshWithContent (string projectContent); + Task<MSBuildResult> Run ( + ProjectConfigurationInfo[] configurations, ILogWriter logWriter, MSBuildVerbosity verbosity, + string[] runTargets, string[] evaluateItems, string[] evaluateProperties, Dictionary<string,string> globalProperties, int taskId + ); + } +} diff --git a/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/MSBuildEvaluatedItem.cs b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/MSBuildEvaluatedItem.cs new file mode 100644 index 0000000000..f948e28109 --- /dev/null +++ b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/MSBuildEvaluatedItem.cs @@ -0,0 +1,56 @@ +// +// MSBuildEvaluatedItem.cs +// +// Author: +// Michael Hutchinson <m.j.hutchinson@gmail.com> +// +// Copyright (c) 2014 Xamarin Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Collections.Generic; +using MonoDevelop.Core.Execution; + +namespace MonoDevelop.Projects.MSBuild +{ + [MessageDataTypeAttribute] + class MSBuildEvaluatedItem + { + public MSBuildEvaluatedItem () + { + } + + public MSBuildEvaluatedItem (string name, string itemSpec) + { + Name = name; + ItemSpec = itemSpec; + Metadata = new Dictionary<string, string> (); + } + + [MessageDataProperty] + public Dictionary<string,string> Metadata { get; set; } + + [MessageDataProperty] + public string ItemSpec { get; set; } + + [MessageDataProperty] + public string Name { get; set; } + } +} diff --git a/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/MSBuildResult.cs b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/MSBuildResult.cs new file mode 100644 index 0000000000..e68b995cf9 --- /dev/null +++ b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/MSBuildResult.cs @@ -0,0 +1,69 @@ +// +// MSBuildResult.cs +// +// Author: +// Michael Hutchinson <m.j.hutchinson@gmail.com> +// +// Copyright (c) 2014 Xamarin Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Collections.Generic; +using MonoDevelop.Core.Execution; + +namespace MonoDevelop.Projects.MSBuild +{ + [MessageDataTypeAttribute] + class MSBuildResult + { + [MessageDataProperty] + MSBuildTargetResult[] errors; + + [MessageDataProperty] + Dictionary<string,string> properties; + + [MessageDataProperty] + Dictionary<string,MSBuildEvaluatedItem[]> items; + + internal MSBuildResult () + { + } + + public MSBuildResult (MSBuildTargetResult[] errors) + { + this.errors = errors; + this.properties = new Dictionary<string,string> (); + this.items = new Dictionary<string,MSBuildEvaluatedItem[]> (); + } + + public MSBuildTargetResult[] Errors { + get { return errors; } + } + + public Dictionary<string,MSBuildEvaluatedItem[]> Items { + get { return items; } + } + + public Dictionary<string, string> Properties { + get { return properties; } + } + } + +} diff --git a/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/MSBuildTargetResult.cs b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/MSBuildTargetResult.cs new file mode 100644 index 0000000000..df0080b9ac --- /dev/null +++ b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/MSBuildTargetResult.cs @@ -0,0 +1,140 @@ +// +// MSBuildTargetResult.cs +// +// Author: +// Lluis Sanchez Gual <lluis@novell.com> +// +// Copyright (c) 2009 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Text; +using MonoDevelop.Core.Execution; + +namespace MonoDevelop.Projects.MSBuild +{ + [MessageDataType] + class MSBuildTargetResult + { + public MSBuildTargetResult () + { + } + + public MSBuildTargetResult ( + string projectFile, bool isWarning, string subcategory, string code, string file, + int lineNumber, int columnNumber, int endLineNumber, int endColumnNumber, + string message, string helpKeyword) + { + ProjectFile = projectFile; + IsWarning = isWarning; + Subcategory = subcategory; + Code = code; + File = file; + LineNumber = lineNumber; + ColumnNumber = columnNumber; + EndLineNumber = endLineNumber; + EndColumnNumber = endColumnNumber; + Message = message; + HelpKeyword = helpKeyword; + } + + [MessageDataProperty] + public string ProjectFile { get; set; } + + [MessageDataProperty] + public bool IsWarning { get; set; } + + [MessageDataProperty] + public string Subcategory { get; set; } + + [MessageDataProperty] + public string Code { get; set; } + + [MessageDataProperty] + public string File { get; set; } + + [MessageDataProperty] + public int LineNumber { get; set; } + + [MessageDataProperty] + public int ColumnNumber { get; set; } + + [MessageDataProperty] + public int EndLineNumber { get; set; } + + [MessageDataProperty] + public int EndColumnNumber { get; set; } + + [MessageDataProperty] + public string Message { get; set; } + + [MessageDataProperty] + public string HelpKeyword { get; set; } + + public override string ToString () + { + var sb = new StringBuilder (); + if (!string.IsNullOrEmpty (File)) { + sb.Append (File); + if (LineNumber > 0) { + //(line) + sb.Append ("("); + sb.Append (LineNumber); + if (ColumnNumber > 0) { + //(line,col) + sb.Append (","); + sb.Append (ColumnNumber); + if (EndColumnNumber > 0) { + if (EndLineNumber > 0) { + //(line,col,line,col) + sb.Append (","); + sb.Append (EndLineNumber); + sb.Append (","); + sb.Append (EndColumnNumber); + } else { + //(line,col-col) + sb.Append ("-"); + sb.Append (EndColumnNumber); + } + } + } else if (EndLineNumber > 0) { + //(line-line) + sb.Append ("-"); + sb.Append (EndLineNumber); + } + sb.Append (")"); + } + sb.Append (": "); + } + if (!string.IsNullOrEmpty (Subcategory)) { + sb.Append (Subcategory); + sb.Append (" "); + } + sb.Append (IsWarning ? "warning" : "error"); + if (!string.IsNullOrEmpty (Code)) { + sb.Append (" "); + sb.Append (Code); + } + sb.Append (": "); + sb.Append (Message); + return sb.ToString (); + } + } +} diff --git a/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/Main.cs b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/Main.cs new file mode 100644 index 0000000000..cfc5126fd2 --- /dev/null +++ b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/Main.cs @@ -0,0 +1,50 @@ +// +// Main.cs +// +// Author: +// Lluis Sanchez Gual <lluis@novell.com> +// +// Copyright (c) 2009 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using System.IO; +using System.Collections; +using System.Runtime.Serialization.Formatters.Binary; +using System.Runtime.Remoting; +using System.Runtime.Remoting.Channels; +using System.Runtime.Remoting.Channels.Tcp; +using System.Threading; +using System.Diagnostics; +using MonoDevelop.Core.Execution; + +namespace MonoDevelop.Projects.MSBuild +{ + class MainClass + { + [STAThread] + public static void Main (string[] args) + { + RemoteProcessServer server = new RemoteProcessServer (); + var builderEngine = new BuildEngine (server); + server.Connect (args, builderEngine); + builderEngine.WaitHandle.WaitOne (); + } + } +} diff --git a/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/MonoDevelop.Projects.MSBuild.Shared.projitems b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/MonoDevelop.Projects.MSBuild.Shared.projitems new file mode 100644 index 0000000000..bd0e54a174 --- /dev/null +++ b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/MonoDevelop.Projects.MSBuild.Shared.projitems @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+ <HasSharedItems>true</HasSharedItems>
+ <SharedGUID>{DB95FF74-275D-4488-84E9-1060527988BF}</SharedGUID>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration">
+ <Import_RootNamespace>MonoDevelop.Projects.MSBuild.Shared</Import_RootNamespace>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="$(MSBuildThisFileDirectory)..\..\MonoDevelop.Core\MonoDevelop.Core.Execution\BinaryMessage.cs">
+ <Link>BinaryMessage.cs</Link>
+ </Compile>
+ <Compile Include="$(MSBuildThisFileDirectory)BuildEngine.Shared.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)RemoteBuildEngineMessages.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)ProjectBuilder.Shared.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)..\..\MonoDevelop.Core\MonoDevelop.Core.Execution\RemoteProcessServer.cs">
+ <Link>RemoteProcessServer.cs</Link>
+ </Compile>
+ <Compile Include="$(MSBuildThisFileDirectory)ILogWriter.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)MSBuildEvaluatedItem.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)MSBuildResult.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)MSBuildTargetResult.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Main.cs" />
+ </ItemGroup>
+</Project>
\ No newline at end of file diff --git a/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/MonoDevelop.Projects.MSBuild.Shared.shproj b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/MonoDevelop.Projects.MSBuild.Shared.shproj new file mode 100644 index 0000000000..3538f4c628 --- /dev/null +++ b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/MonoDevelop.Projects.MSBuild.Shared.shproj @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{DB95FF74-275D-4488-84E9-1060527988BF}</ProjectGuid> + </PropertyGroup> + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> + <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" /> + <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" /> + <Import Project="MonoDevelop.Projects.MSBuild.Shared.projitems" Label="Shared" /> + <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" /> +</Project>
\ No newline at end of file diff --git a/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/ProjectBuilder.Shared.cs b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/ProjectBuilder.Shared.cs new file mode 100644 index 0000000000..3a5a54fe9e --- /dev/null +++ b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/ProjectBuilder.Shared.cs @@ -0,0 +1,186 @@ +//
+// ProjectBuilder.Shared.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@novell.com>
+// Michael Hutchinson <m.j.hutchinson@gmail.com>
+//
+// Copyright (c) 2009-2011 Novell, Inc (http://www.novell.com)
+// Copyright (c) 2011-2015 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using Microsoft.Build.Framework;
+using System.Xml;
+using System.IO;
+using System;
+using System.Text;
+using System.Threading;
+using MonoDevelop.Core.Execution;
+
+namespace MonoDevelop.Projects.MSBuild
+{
+ partial class ProjectBuilder
+ {
+ ILogWriter currentLogWriter;
+ StringBuilder log = new StringBuilder ();
+ bool flushingLog;
+ Timer flushTimer;
+ object flushLogLock = new object ();
+ const int LogFlushTimeout = 100;
+
+ public void Dispose ()
+ {
+ buildEngine.UnloadProject (file);
+ }
+
+ public void Refresh ()
+ {
+ buildEngine.UnloadProject (file);
+ }
+
+ public void RefreshWithContent (string projectContent)
+ {
+ buildEngine.UnloadProject (file);
+ buildEngine.SetUnsavedProjectContent (file, projectContent);
+ }
+
+ /// <summary>
+ /// Prepares the logging infrastructure
+ /// </summary>
+ void InitLogger (ILogWriter logWriter)
+ {
+ currentLogWriter = logWriter;
+ if (currentLogWriter != null) { + log.Clear (); + flushingLog = false; + flushTimer = new Timer (o => FlushLog ());
+ }
+ }
+
+ /// <summary>
+ /// Flushes the log that has not yet been sent and disposes the logging infrastructure
+ /// </summary>
+ void DisposeLogger ()
+ {
+ if (currentLogWriter != null) { + flushTimer.Dispose (); + flushTimer = null; + FlushLog (); + currentLogWriter = null;
+ }
+ }
+
+ void LogWriteLine (string txt)
+ {
+ if (currentLogWriter != null) {
+ lock (log) {
+ // Append the line to the log, and schedule the flush of the log, unless it has already been done
+ log.AppendLine (txt);
+ if (!flushingLog) {
+ // Flush the log after 100ms
+ flushingLog = true;
+ flushTimer.Change (LogFlushTimeout, Timeout.Infinite);
+ }
+ }
+ }
+ }
+
+ void FlushLog ()
+ {
+ // We need a lock for the whole method here because it is called from the timer
+ // and from DisposeLogger, and we want to make sure a flush is complete before
+ // trying another one
+
+ lock (flushLogLock) { + string txt; + lock (log) {
+ // Don't flush the log inside the lock since that would prevent LogWriteLine from writing
+ // more log while the current log is being flushed (that would slow down the whole build) + txt = log.ToString (); + log.Clear (); + flushingLog = false; + } + if (txt.Length > 0 && currentLogWriter != null) + currentLogWriter.Write (txt);
+ }
+ }
+
+ LoggerVerbosity GetVerbosity (MSBuildVerbosity verbosity)
+ {
+ switch (verbosity) {
+ case MSBuildVerbosity.Quiet:
+ return LoggerVerbosity.Quiet;
+ case MSBuildVerbosity.Minimal:
+ return LoggerVerbosity.Minimal;
+ default:
+ return LoggerVerbosity.Normal;
+ case MSBuildVerbosity.Detailed:
+ return LoggerVerbosity.Detailed;
+ case MSBuildVerbosity.Diagnostic:
+ return LoggerVerbosity.Diagnostic;
+ }
+ }
+
+ //from MSBuildProjectService
+ static string UnescapeString (string str)
+ {
+ int i = str.IndexOf ('%');
+ while (i != -1 && i < str.Length - 2) {
+ int c;
+ if (int.TryParse (str.Substring (i+1, 2), System.Globalization.NumberStyles.HexNumber, null, out c))
+ str = str.Substring (0, i) + (char) c + str.Substring (i + 3);
+ i = str.IndexOf ('%', i + 1);
+ }
+ return str;
+ }
+
+ string GenerateSolutionConfigurationContents (ProjectConfigurationInfo[] configurations)
+ {
+ // can't use XDocument because of the 2.0 builder
+ // and don't just build a string because things may need escaping
+
+ var doc = new XmlDocument ();
+ var root = doc.CreateElement ("SolutionConfiguration");
+ doc.AppendChild (root);
+ foreach (var config in configurations) {
+ var el = doc.CreateElement ("ProjectConfiguration");
+ root.AppendChild (el);
+ el.SetAttribute ("Project", config.ProjectGuid);
+ el.SetAttribute ("AbsolutePath", config.ProjectFile);
+ el.SetAttribute ("BuildProjectInSolution", config.Enabled ? "True" : "False");
+ el.InnerText = string.Format (config.Configuration + "|" + config.Platform);
+ }
+
+ //match MSBuild formatting
+ var options = new XmlWriterSettings {
+ Indent = true,
+ IndentChars = "",
+ OmitXmlDeclaration = true,
+ };
+ using (var sw = new StringWriter ())
+ using (var xw = XmlWriter.Create (sw, options)) {
+ doc.WriteTo (xw);
+ xw.Flush ();
+ return sw.ToString ();
+ }
+ }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/RemoteBuildEngineMessages.cs b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/RemoteBuildEngineMessages.cs new file mode 100644 index 0000000000..23f22f4b16 --- /dev/null +++ b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.Projects.MSBuild.Shared/RemoteBuildEngineMessages.cs @@ -0,0 +1,195 @@ +// +// RemoteBuildEngineMessages.cs +// +// Author: +// Lluis Sanchez Gual <lluis@xamarin.com> +// +// Copyright (c) 2016 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using System.Collections.Generic; +using MonoDevelop.Core.Execution; + +namespace MonoDevelop.Projects.MSBuild +{ + [MessageDataTypeAttribute] + class InitializeRequest: BinaryMessage + { + [MessageDataProperty] + public int IdeProcessId { get; set; } + + [MessageDataProperty] + public string CultureName { get; set; } + + [MessageDataProperty] + public Dictionary<string, string> GlobalProperties { get; set; } + } + + [MessageDataTypeAttribute] + class LoadProjectRequest: BinaryMessage<LoadProjectResponse> + { + [MessageDataProperty] + public string ProjectFile { get; set; } + } + + [MessageDataTypeAttribute] + class LoadProjectResponse: BinaryMessage + { + [MessageDataProperty] + public int ProjectId { get; set; } + } + + [MessageDataTypeAttribute] + class UnloadProjectRequest: BinaryMessage + { + [MessageDataProperty] + public int ProjectId { get; set; } + } + + [MessageDataTypeAttribute] + class CancelTaskRequest: BinaryMessage + { + [MessageDataProperty] + public int TaskId { get; set; } + } + + [MessageDataTypeAttribute] + class SetGlobalPropertiesRequest: BinaryMessage + { + [MessageDataProperty] + public Dictionary<string, string> Properties { get; set; } + } + + [MessageDataTypeAttribute] + class PingRequest: BinaryMessage + { + [MessageDataProperty] + public int TaskId = 1; + } + + [MessageDataTypeAttribute] + class DisposeRequest: BinaryMessage + { + } + + [MessageDataTypeAttribute] + class DisposeProjectRequest: BinaryMessage + { + [MessageDataProperty] + public int ProjectId { get; set; } + } + + [MessageDataTypeAttribute] + class RefreshProjectRequest: BinaryMessage + { + [MessageDataProperty] + public int ProjectId { get; set; } + } + + [MessageDataTypeAttribute] + class RefreshWithContentRequest: BinaryMessage + { + [MessageDataProperty] + public int ProjectId { get; set; } + + [MessageDataProperty] + public string Content { get; set; } + } + + [MessageDataTypeAttribute] + class RunProjectRequest: BinaryMessage<RunProjectResponse> + { + [MessageDataProperty] + public int ProjectId { get; set; } + + [MessageDataProperty] + public string Content { get; set; } + + [MessageDataProperty] + public ProjectConfigurationInfo [] Configurations { get; set; } + + [MessageDataProperty] + public int LogWriterId { get; set; } + + [MessageDataProperty] + public MSBuildVerbosity Verbosity { get; set; } + + [MessageDataProperty] + public string [] RunTargets { get; set; } + + [MessageDataProperty] + public string [] EvaluateItems { get; set; } + + [MessageDataProperty] + public string [] EvaluateProperties { get; set; } + + [MessageDataProperty] + public Dictionary<string, string> GlobalProperties { get; set; } + + [MessageDataProperty] + public int TaskId { get; set; } + } + + [MessageDataTypeAttribute] + class RunProjectResponse : BinaryMessage + { + [MessageDataProperty] + public MSBuildResult Result { get; set; } + } + + [MessageDataTypeAttribute] + class LogMessage : BinaryMessage + { + [MessageDataProperty] + public int LoggerId { get; set; } + + [MessageDataProperty] + public string Text { get; set; } + } + + public enum MSBuildVerbosity + { + Quiet, + Minimal, + Normal, + Detailed, + Diagnostic + } + + [MessageDataTypeAttribute] + class ProjectConfigurationInfo + { + [MessageDataProperty] + public string ProjectFile { get; set; } + + [MessageDataProperty] + public string ProjectGuid { get; set; } + + [MessageDataProperty] + public string Configuration { get; set; } + + [MessageDataProperty] + public string Platform { get; set; } + + [MessageDataProperty] + public bool Enabled { get; set; } + } +} + |