diff options
author | Lluis Sanchez <lluis@xamarin.com> | 2016-07-13 16:39:30 +0300 |
---|---|---|
committer | Lluis Sanchez <lluis@xamarin.com> | 2016-07-13 16:39:30 +0300 |
commit | d04e8a42146c183fae438a196bd7213517ce9de7 (patch) | |
tree | e3a86c18e2817d67075523e8f34fdce9c8605f23 /main/src/core/MonoDevelop.Core | |
parent | 2b0cf79be1c546ec18129188aecde7e3bcd3821d (diff) | |
parent | 7446a7c8606c95180d7f2c89461ee3d3d44ec05d (diff) |
Merge remote-tracking branch 'origin/run-configurations'
Diffstat (limited to 'main/src/core/MonoDevelop.Core')
44 files changed, 2802 insertions, 313 deletions
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.AddIns/ExecutionModeSetNode.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.AddIns/ExecutionModeSetNode.cs index e9dfe7addd..0dd6fca37d 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.AddIns/ExecutionModeSetNode.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.AddIns/ExecutionModeSetNode.cs @@ -32,6 +32,7 @@ using MonoDevelop.Core.Execution; namespace MonoDevelop.Core.AddIns { [ExtensionNodeChild (typeof(ExecutionModeNode), "Mode")] + [ExtensionNodeChild (typeof(TypeExtensionNode), "ModeSetType")] class ExecutionModeSetNode: ExtensionNode, IExecutionModeSet { [NodeAttribute ("_name", Localizable=true)] @@ -43,8 +44,16 @@ namespace MonoDevelop.Core.AddIns public IEnumerable<IExecutionMode> ExecutionModes { get { - foreach (ExecutionModeNode node in ChildNodes) - yield return node; + foreach (ExtensionNode node in ChildNodes) { + if (node is ExecutionModeNode) + yield return (ExecutionModeNode)node; + else if (node is TypeExtensionNode) { + var mset = ((TypeExtensionNode)node).GetInstance () as IExecutionModeSet; + if (mset != null) + foreach (var h in mset.ExecutionModes) + yield return h; + } + } } } } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/DotNetExecutionCommand.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/DotNetExecutionCommand.cs index d6d06cb63e..2c30d2900c 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/DotNetExecutionCommand.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/DotNetExecutionCommand.cs @@ -74,5 +74,9 @@ namespace MonoDevelop.Core.Execution public string RuntimeArguments { get; set; } public IList<string> UserAssemblyPaths { get; set; } + + public bool PauseConsoleOutput { get; set; } + + public bool ExternalConsole { get; set; } } } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/IExecutionHandler.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/IExecutionHandler.cs index fbde4d74ec..1d27b28859 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/IExecutionHandler.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/IExecutionHandler.cs @@ -29,6 +29,9 @@ using System; using System.Collections.Generic; using System.Threading; +using System.Threading.Tasks; +using Mono.Addins; +using MonoDevelop.Projects; namespace MonoDevelop.Core.Execution { @@ -70,4 +73,9 @@ namespace MonoDevelop.Core.Execution /// </summary> ExecutionTarget Target { get; } } + + public interface IConfigurableExecutionHandler + { + Task<IExecutionHandler> Configure (IRunTarget target, MonoDevelop.Projects.ExecutionContext context, ConfigurationSelector configuration, RunConfiguration runConfiguration); + } } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/IExecutionModeSet.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/IExecutionModeSet.cs index bcad34dda9..ab5337b8fe 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/IExecutionModeSet.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/IExecutionModeSet.cs @@ -54,7 +54,7 @@ namespace MonoDevelop.Core.Execution class DefaultExecutionModeSet: IExecutionModeSet { public string Name { - get { return GettextCatalog.GetString ("Default"); } + get { return GettextCatalog.GetString ("Run"); } } public IEnumerable<IExecutionMode> ExecutionModes { diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessService.cs index a84f5846d7..c04dfa427e 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessService.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessService.cs @@ -222,9 +222,17 @@ namespace MonoDevelop.Core.Execution if (environmentVariables != null) foreach (KeyValuePair<string, string> kvp in environmentVariables) psi.EnvironmentVariables [kvp.Key] = kvp.Value; - ProcessWrapper pw = StartProcess (psi, console.Out, console.Error, null); - new ProcessMonitor (console, pw.ProcessAsyncOperation, exited); - return pw.ProcessAsyncOperation; + try { + ProcessWrapper pw = StartProcess (psi, console.Out, console.Error, null); + new ProcessMonitor (console, pw.ProcessAsyncOperation, exited); + return pw.ProcessAsyncOperation; + } catch (Exception ex) { + // If the process can't be started, dispose the console now since ProcessMonitor won't do it + console.Error.WriteLine (GettextCatalog.GetString ("The application could not be started")); + LoggingService.LogError ("Could not start process for command: " + psi.FileName + " " + psi.Arguments, ex); + console.Dispose (); + return NullProcessAsyncOperation.Failure; + } } public IExecutionHandler GetDefaultExecutionHandler (ExecutionCommand command) diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/ClassDataType.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/ClassDataType.cs index c1d0954759..944d53eb36 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/ClassDataType.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/ClassDataType.cs @@ -123,6 +123,7 @@ namespace MonoDevelop.Core.Serialization prop.SkipEmpty = at.SkipEmpty; prop.ReadOnly = at.ReadOnly; prop.WriteOnly = at.WriteOnly; + prop.WrapObject = at.WrapObject; if (prop.ExpandedCollection) { ICollectionHandler handler = Context.GetCollectionHandler (memberType); diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/DataValue.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/DataValue.cs index 68dd002dce..2f4f290364 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/DataValue.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/DataValue.cs @@ -34,7 +34,7 @@ namespace MonoDevelop.Core.Serialization public class DataValue: DataNode { string value; - bool storeAsAttribute; + bool? storeAsAttribute; public DataValue (string name, string value) { @@ -45,8 +45,8 @@ namespace MonoDevelop.Core.Serialization public string Value { get { return value; } } - - internal bool StoreAsAttribute { + + internal bool? StoreAsAttribute { get { return storeAsAttribute; } @@ -54,7 +54,15 @@ namespace MonoDevelop.Core.Serialization storeAsAttribute = value; } } - + + internal bool StoreAsAttributeRequired { + get { return storeAsAttribute.HasValue && storeAsAttribute.Value; } + } + + internal bool StoreAsElementRequired { + get { return storeAsAttribute.HasValue && !storeAsAttribute.Value; } + } + public override string ToString () { return ToString (0); diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/ItemProperty.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/ItemProperty.cs index 8e88dc3b2d..219dfb21ed 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/ItemProperty.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/ItemProperty.cs @@ -135,6 +135,8 @@ namespace MonoDevelop.Core.Serialization get { return dataType; } set { CheckReadOnly (); dataType = value; } } + + public bool WrapObject { get; set; } public bool SkipEmpty { get; set; } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/ItemPropertyAttribute.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/ItemPropertyAttribute.cs index bbd9a3c7b5..b24faf0bc2 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/ItemPropertyAttribute.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/ItemPropertyAttribute.cs @@ -98,7 +98,9 @@ namespace MonoDevelop.Core.Serialization get { return writeOnly; } set { writeOnly = value; } } - + + public bool WrapObject { get; set; } = true; + public Type FallbackType { get { return fallbackType; } set { fallbackType = value; } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/XmlDataSerializer.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/XmlDataSerializer.cs index 4765c079fc..909dc252fd 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/XmlDataSerializer.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/XmlDataSerializer.cs @@ -163,20 +163,20 @@ namespace MonoDevelop.Core.Serialization protected virtual void WriteAttributes (XmlElement elem, DataItem item) { - if (StoreAllInElements) - return; + var defaultIsAtt = item.UniqueNames && !StoreAllInElements; foreach (DataNode data in item.ItemData) { DataValue val = data as DataValue; - if (val != null && (item.UniqueNames || val.StoreAsAttribute)) + if (val != null && (StoreAsAttribute (val) || (defaultIsAtt && !val.StoreAsElementRequired))) WriteAttribute (elem, val.Name, val.Value); } } protected virtual void WriteAttributes (XmlWriter writer, DataItem item) { + var defaultIsAtt = item.UniqueNames && !StoreAllInElements; foreach (DataNode data in item.ItemData) { DataValue val = data as DataValue; - if (val != null && (item.UniqueNames || val.StoreAsAttribute) && StoreAsAttribute (val)) + if (val != null && (StoreAsAttribute (val) || (defaultIsAtt && !val.StoreAsElementRequired))) WriteAttribute (writer, val.Name, val.Value); } } @@ -193,33 +193,21 @@ namespace MonoDevelop.Core.Serialization protected virtual void WriteChildren (XmlWriter writer, DataItem item) { - if (item.UniqueNames) { - foreach (DataNode data in item.ItemData) { - if (!(data is DataValue) || !StoreAsAttribute ((DataValue)data)) - WriteChild (writer, data); - } - } else { - foreach (DataNode data in item.ItemData) { - DataValue dval = data as DataValue; - if (dval == null || !dval.StoreAsAttribute || !StoreAsAttribute (dval)) - WriteChild (writer, data); - } + var defaultIsAtt = item.UniqueNames && !StoreAllInElements; + foreach (DataNode data in item.ItemData) { + DataValue dval = data as DataValue; + if (dval == null || !(StoreAsAttribute (dval) || (defaultIsAtt && !dval.StoreAsElementRequired))) + WriteChild (writer, data); } } protected virtual void WriteChildren (XmlElement elem, DataItem item) { - if (item.UniqueNames) { - foreach (DataNode data in item.ItemData) { - if (!(data is DataValue) || !StoreAsAttribute ((DataValue)data)) - WriteChild (elem, data); - } - } else { - foreach (DataNode data in item.ItemData) { - DataValue dval = data as DataValue; - if (dval == null || !dval.StoreAsAttribute || !StoreAsAttribute (dval)) - WriteChild (elem, data); - } + var defaultIsAtt = item.UniqueNames && !StoreAllInElements; + foreach (DataNode data in item.ItemData) { + DataValue dval = data as DataValue; + if (dval == null || !(StoreAsAttribute (dval) || (defaultIsAtt && !dval.StoreAsElementRequired))) + WriteChild (elem, data); } } @@ -235,10 +223,12 @@ namespace MonoDevelop.Core.Serialization public virtual bool StoreAsAttribute (DataValue val) { - if (StoreAllInElements) + if (val.StoreAsAttributeRequired) + return true; + else if (StoreAllInElements) return StoreInElementExceptions != null && ((IList)StoreInElementExceptions).Contains (val.Name); else - return true; + return false; } protected virtual XmlConfigurationWriter GetChildWriter (DataNode data) diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.addin.xml b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.addin.xml index 95b81c4706..c575762361 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.addin.xml +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.addin.xml @@ -160,8 +160,9 @@ <Extension path = "/MonoDevelop/Core/ExecutionModes"> -<!-- <Mode id="Default" _name="Default" class="MonoDevelop.Core.Execution.DefaultExecutionHandlerFactory"/>--> - <ModeSetType class="MonoDevelop.Core.Assemblies.CustomRuntimeExecutionModeSet"/> + <ModeSet id="Run" _name="Run" /> + <ModeSet id="Debug" _name="Debug" /> + <ModeSet id="Profile" _name="Profile" /> </Extension> <Extension path = "/MonoDevelop/Core/Runtimes"> diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj index 00d711ef7e..e025833a7f 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj @@ -210,7 +210,6 @@ <Compile Include="MonoDevelop.Core.Assemblies\SystemAssemblyService.cs" /> <Compile Include="MonoDevelop.Core.Assemblies\MonoRuntimeInfo.cs" /> <Compile Include="MonoDevelop.Core.Execution\IExecutionModeSet.cs" /> - <Compile Include="MonoDevelop.Core.Assemblies\CustomRuntimeExecutionModeSet.cs" /> <Compile Include="MonoDevelop.Core.Execution\ExecutionMode.cs" /> <Compile Include="MonoDevelop.Core.Execution\ExecutionCommand.cs" /> <Compile Include="MonoDevelop.Core.Execution\DotNetExecutionCommand.cs" /> @@ -562,6 +561,19 @@ <Compile Include="MonoDevelop.Core.Execution\RemoteProcessConnection.cs" /> <Compile Include="MonoDevelop.Core.Execution\RemoteProcessServer.cs" /> <Compile Include="MonoDevelop.Projects\AssemblyReference.cs" /> + <Compile Include="MonoDevelop.Projects\SolutionItemRunConfiguration.cs" /> + <Compile Include="MonoDevelop.Projects\ProjectRunConfiguration.cs" /> + <Compile Include="MonoDevelop.Projects\RunConfigurationCollection.cs" /> + <Compile Include="MonoDevelop.Projects\AssemblyRunConfiguration.cs" /> + <Compile Include="MonoDevelop.Projects\MonoExecutionParameters.cs" /> + <Compile Include="MonoDevelop.Projects\SolutionRunConfiguration.cs" /> + <Compile Include="MonoDevelop.Projects\SingleItemSolutionRunConfiguration.cs" /> + <Compile Include="MonoDevelop.Projects\MultiItemSolutionRunConfiguration.cs" /> + <Compile Include="MonoDevelop.Projects\SolutionRunConfigurationCollection.cs" /> + <Compile Include="MonoDevelop.Projects\EnvironmentVariableCollection.cs" /> + <Compile Include="MonoDevelop.Projects\RunConfiguration.cs" /> + <Compile Include="MonoDevelop.Projects\IRunTarget.cs" /> + <Compile Include="MonoDevelop.Projects\ProcessRunConfiguration.cs" /> </ItemGroup> <ItemGroup> <None Include="Makefile.am" /> diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/DefaultMSBuildEngine.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/DefaultMSBuildEngine.cs index aec39b743e..e0a76f53ad 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/DefaultMSBuildEngine.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/DefaultMSBuildEngine.cs @@ -173,13 +173,18 @@ namespace MonoDevelop.Projects.MSBuild void EvaluateProject (ProjectInfo pi, MSBuildEvaluationContext context) { context.InitEvaluation (pi.Project); - EvaluateObjects (pi, context, pi.Project.GetAllObjects (), false); - EvaluateObjects (pi, context, pi.Project.GetAllObjects (), true); + var objects = pi.Project.GetAllObjects (); + + // If there is a .user project file load it using a fake import item added at the end of the objects list + if (File.Exists (pi.Project.FileName + ".user")) + objects = objects.Concat (new MSBuildImport {Project = pi.Project.FileName + ".user" }); + + EvaluateObjects (pi, context, objects, false); + EvaluateObjects (pi, context, objects, true); } void EvaluateProject (ProjectInfo pi, MSBuildEvaluationContext context, bool evalItems) { - // XmlDocument is not thread safe, so we need to lock while evaluating context.InitEvaluation (pi.Project); EvaluateObjects (pi, context, pi.Project.GetAllObjects (), evalItems); } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/IMSBuildPropertySet.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/IMSBuildPropertySet.cs index 386b018710..e466073a95 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/IMSBuildPropertySet.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/IMSBuildPropertySet.cs @@ -57,6 +57,7 @@ namespace MonoDevelop.Projects.MSBuild DataSerializer ser = new DataSerializer (Services.ProjectService.DataContext); var props = Services.ProjectService.DataContext.GetProperties (ser.SerializationContext, ob); XmlConfigurationWriter cwriter = null; + XmlDocument xdoc = null; var mso = pset as IMSBuildProjectObject; if (mso != null && mso.ParentProject != null) @@ -84,13 +85,14 @@ namespace MonoDevelop.Projects.MSBuild } else { var val = prop.GetValue (ob); if (val != null) { - if (cwriter == null) - cwriter = new XmlConfigurationWriter { Namespace = MSBuildProject.Schema }; - var w = new StringWriter (); + if (cwriter == null) { + cwriter = new XmlConfigurationWriter { Namespace = MSBuildProject.Schema, StoreAllInElements = true }; + xdoc = new XmlDocument (); + } var data = prop.Serialize (ser.SerializationContext, ob, val); if (data != null) { - cwriter.Write (new XmlTextWriter (w), data); - pset.SetValue (prop.Name, w.ToString ()); + var elem = cwriter.Write (xdoc, data); + pset.SetValue (prop.Name, prop.WrapObject ? elem.OuterXml : elem.InnerXml); } else pset.RemoveProperty (prop.Name); } else @@ -130,6 +132,8 @@ namespace MonoDevelop.Projects.MSBuild var val = pset.GetValue (prop.Name); if (!string.IsNullOrEmpty (val)) { try { + if (!prop.WrapObject) + val = "<a>" + val + "</a>"; var data = XmlConfigurationReader.DefaultReader.Read (new XmlTextReader (new StringReader (val))); if (prop.HasSetter && prop.DataType.CanCreateInstance) { readVal = prop.Deserialize (ser.SerializationContext, ob, data); diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildObject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildObject.cs index 4b8de4f6a6..40894626db 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildObject.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildObject.cs @@ -60,15 +60,16 @@ namespace MonoDevelop.Projects.MSBuild internal object EndInnerWhitespace { get; set; } internal virtual bool PreferEmptyElement { get { return true; } } + internal virtual bool ContentRequiredForEvaluation { get { return true; } } - #if ATTR_STATS +#if ATTR_STATS public static StringCounter UnknownAtts = new StringCounter (); public static StringCounter KnownAttOrder = new StringCounter (); - #endif +#endif internal override void Read (MSBuildXmlReader reader) { - if (reader.ForEvaluation) { + if (reader.ForEvaluation && !ContentRequiredForEvaluation) { if (reader.MoveToFirstAttribute ()) { do { ReadAttribute (reader.LocalName, reader.Value); @@ -319,7 +320,7 @@ namespace MonoDevelop.Projects.MSBuild internal virtual void ReadChildElement (MSBuildXmlReader reader) { - if (reader.ForEvaluation) + if (reader.ForEvaluation && !ContentRequiredForEvaluation) reader.Skip (); else { var n = new MSBuildXmlElement (); diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectExtensions.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectExtensions.cs index 2f0a36142a..104282143e 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectExtensions.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectExtensions.cs @@ -45,6 +45,12 @@ namespace MonoDevelop.Projects.MSBuild base.Read (reader); } + internal override bool ContentRequiredForEvaluation { + get { + return false; + } + } + internal override string GetElementName () { return "ProjectExtensions"; diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildPropertyGroup.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildPropertyGroup.cs index de81e5f52c..ae3e2f1dfd 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildPropertyGroup.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildPropertyGroup.cs @@ -259,6 +259,11 @@ namespace MonoDevelop.Projects.MSBuild internal IPropertyGroupListener PropertyGroupListener { get; set; } + internal void UnlinkFromProjectInstance () + { + PropertyGroupListener = null; + } + MSBuildProperty FindExistingProperty (int index, int inc) { while (index >= 0 && index < propertyOrder.Count) { diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildTask.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildTask.cs index 95716a4644..36a7d28a83 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildTask.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildTask.cs @@ -50,6 +50,12 @@ namespace MonoDevelop.Projects.MSBuild this.Name = name; } + internal override bool ContentRequiredForEvaluation { + get { + return false; + } + } + static readonly string [] knownAttributes = { "Condition", "Label" }; internal override string [] GetKnownAttributes () diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/AssemblyRunConfiguration.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/AssemblyRunConfiguration.cs new file mode 100644 index 0000000000..6a970419ff --- /dev/null +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/AssemblyRunConfiguration.cs @@ -0,0 +1,137 @@ +// +// DotNetRunConfiguration.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 System.Xml.Linq; +using MonoDevelop.Core; +using MonoDevelop.Core.StringParsing; +using MonoDevelop.Projects.MSBuild; +using MonoDevelop.Core.Serialization; +using System.Linq; +using MonoDevelop.Core.Execution; + +namespace MonoDevelop.Projects +{ + public class AssemblyRunConfiguration: ProcessRunConfiguration + { + MonoExecutionParameters monoParameters = new MonoExecutionParameters (); + + public AssemblyRunConfiguration (string name): base (name) + { + } + + internal protected override void Initialize (Project project) + { + base.Initialize (project); + StartAction = StartActions.Project; + } + + [ItemProperty (DefaultValue = "")] + public string StartAction { get; set; } + + [ItemProperty (DefaultValue = "")] + public FilePath StartProgram { get; set; } = ""; + + public class StartActions + { + public const string Project = "Project"; + public const string Program = "Program"; + } + + public override string Summary { + get { + string envVars = null; + if (EnvironmentVariables.Count > 0) { + var v = EnvironmentVariables.First (); + envVars = v.Key + "=" + v.Value; + if (EnvironmentVariables.Count > 1) + envVars += "..."; + } + if (StartAction == StartActions.Project) { + if (!string.IsNullOrEmpty (StartArguments) && envVars != null) + return GettextCatalog.GetString ("Start the project with arguments '{0}' and environment variables '{1}'", StartArguments, envVars); + else if (!string.IsNullOrEmpty (StartArguments)) + return GettextCatalog.GetString ("Start the project with arguments '{0}'", StartArguments); + else if (envVars != null) + return GettextCatalog.GetString ("Start the project with environment variables '{0}''", envVars); + else + return GettextCatalog.GetString ("Start the project"); + } else { + if (StartProgram.IsNullOrEmpty) + return GettextCatalog.GetString ("Selected startup program is not valid"); + var app = StartProgram.FileName; + if (!string.IsNullOrEmpty (StartArguments) && EnvironmentVariables.Count > 0) + return GettextCatalog.GetString ("Run {0} with arguments '{1}' and custom environment variables '{2}'", app, StartArguments, envVars); + else if (!string.IsNullOrEmpty (StartArguments)) + return GettextCatalog.GetString ("Run {0} with arguments '{1}'", app, StartArguments); + else if (envVars != null) + return GettextCatalog.GetString ("Run {0} with environment variables '{1}'", app, envVars); + else + return GettextCatalog.GetString ("Run {0}", app); + } + } + } + + public bool IsEmpty { + get { return string.IsNullOrEmpty (StartArguments) && string.IsNullOrEmpty (StartWorkingDirectory) && StartAction == StartActions.Project && EnvironmentVariables.Count == 0 && string.IsNullOrEmpty (TargetRuntimeId); } + } + + internal protected override void Read (IPropertySet pset) + { + base.Read (pset); + pset.ReadObjectProperties (monoParameters, monoParameters.GetType (), false); + } + + internal protected override void Write (IPropertySet pset) + { + pset.SetPropertyOrder ("StartAction", "StartProgram", "StartArguments", "StartWorkingDirectory", "ExternalConsole", "ConsolePause", "EnvironmentVariables"); + pset.WriteObjectProperties (monoParameters, monoParameters.GetType (), false); + base.Write (pset); + } + + public MonoExecutionParameters MonoParameters { + get { return monoParameters; } + set { monoParameters = value; } + } + + [ItemProperty (DefaultValue = "")] + public string TargetRuntimeId { get; set; } = ""; + + protected override void OnCopyFrom (ProjectRunConfiguration config, bool isRename) + { + base.OnCopyFrom (config, isRename); + + var other = (AssemblyRunConfiguration)config; + + StartProgram = other.StartProgram; + StartAction = other.StartAction; + monoParameters = other.monoParameters.Clone (); + TargetRuntimeId = other.TargetRuntimeId; + } + } +} + diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CompiledAssemblyProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CompiledAssemblyProject.cs index 6b5226d49c..bd2a34afa5 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CompiledAssemblyProject.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CompiledAssemblyProject.cs @@ -143,7 +143,7 @@ namespace MonoDevelop.Projects return Task.FromResult (BuildResult.CreateSuccess ()); } - protected async override Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) + protected async override Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) { ProjectConfiguration conf = (ProjectConfiguration) GetConfiguration (configuration); monitor.Log.WriteLine (GettextCatalog.GetString ("Running {0} ...", FileName)); @@ -178,7 +178,7 @@ namespace MonoDevelop.Projects } } - protected override bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration) + protected override bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) { ProjectConfiguration config = (ProjectConfiguration) GetConfiguration (configuration); if (config == null) diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs index 1c35c9fe5b..2efcbbca18 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs @@ -142,14 +142,12 @@ namespace MonoDevelop.Projects DotNetProjectConfiguration configDebug = CreateConfiguration ("Debug" + platformSuffix, ConfigurationKind.Debug) as DotNetProjectConfiguration; DefineSymbols (configDebug.CompilationParameters, projectOptions, "DefineConstantsDebug"); configDebug.ExternalConsole = externalConsole; - configDebug.PauseConsoleOutput = externalConsole; Configurations.Add (configDebug); DotNetProjectConfiguration configRelease = CreateConfiguration ("Release" + platformSuffix, ConfigurationKind.Release) as DotNetProjectConfiguration; DefineSymbols (configRelease.CompilationParameters, projectOptions, "DefineConstantsRelease"); configRelease.CompilationParameters.RemoveDefineSymbol ("DEBUG"); configRelease.ExternalConsole = externalConsole; - configRelease.PauseConsoleOutput = externalConsole; Configurations.Add (configRelease); } @@ -1027,6 +1025,10 @@ namespace MonoDevelop.Projects return conf; } + protected override ProjectRunConfiguration OnCreateRunConfiguration (string name) + { + return new AssemblyRunConfiguration (name); + } protected override FilePath OnGetOutputFileName (ConfigurationSelector configuration) { @@ -1110,9 +1112,15 @@ namespace MonoDevelop.Projects .Where (d => !string.IsNullOrEmpty (d)).ToList (); } + [Obsolete("Use the overload that takes a RunConfiguration")] public ExecutionCommand CreateExecutionCommand (ConfigurationSelector configSel, DotNetProjectConfiguration configuration) { - return ProjectExtension.OnCreateExecutionCommand (configSel, configuration); + return CreateExecutionCommand (configSel, configuration, GetDefaultRunConfiguration () as ProjectRunConfiguration); + } + + public ExecutionCommand CreateExecutionCommand (ConfigurationSelector configSel, DotNetProjectConfiguration configuration, ProjectRunConfiguration runConfiguration) + { + return ProjectExtension.OnCreateExecutionCommand (configSel, configuration, runConfiguration); } internal protected virtual ExecutionCommand OnCreateExecutionCommand (ConfigurationSelector configSel, DotNetProjectConfiguration configuration) @@ -1125,16 +1133,85 @@ namespace MonoDevelop.Projects return cmd; } - protected override bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration) + internal protected virtual ExecutionCommand OnCreateExecutionCommand (ConfigurationSelector configSel, DotNetProjectConfiguration configuration, ProjectRunConfiguration runConfiguration) { - DotNetProjectConfiguration config = (DotNetProjectConfiguration) GetConfiguration (configuration); + ExecutionCommand rcmd; + var rc = runConfiguration as AssemblyRunConfiguration; + if (rc != null && rc.StartAction == AssemblyRunConfiguration.StartActions.Program) { + var pcmd = Runtime.ProcessService.CreateCommand (rc.StartProgram); + pcmd.Arguments = rc.StartArguments; + pcmd.WorkingDirectory = rc.StartWorkingDirectory; + pcmd.EnvironmentVariables = rc.EnvironmentVariables; + rcmd = pcmd; + } else { +#pragma warning disable 618 // Type or member is obsolete + rcmd = ProjectExtension.OnCreateExecutionCommand (configSel, configuration); +#pragma warning restore 618 // Type or member is obsolete + } + + var cmd = rcmd as DotNetExecutionCommand; + if (cmd == null) + return rcmd; + + if (rc != null) { + // Don't directly overwrite the settings, since those may have been set by the OnCreateExecutionCommand + // overload that doesn't take a runConfiguration. + + string monoOptions; + rc.MonoParameters.GenerateOptions (cmd.EnvironmentVariables, out monoOptions); + cmd.RuntimeArguments = monoOptions; + if (!string.IsNullOrEmpty (rc.StartArguments)) + cmd.Arguments = rc.StartArguments; + if (!rc.StartWorkingDirectory.IsNullOrEmpty) + cmd.WorkingDirectory = rc.StartWorkingDirectory; + foreach (var env in rc.EnvironmentVariables) + cmd.EnvironmentVariables [env.Key] = env.Value; + cmd.PauseConsoleOutput = rc.PauseConsoleOutput; + cmd.ExternalConsole = rc.ExternalConsole; + cmd.TargetRuntime = Runtime.SystemAssemblyService.GetTargetRuntime (rc.TargetRuntimeId); + } + return cmd; + } + + protected override bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) + { + DotNetProjectConfiguration config = (DotNetProjectConfiguration)GetConfiguration (configuration); if (config == null) return false; - ExecutionCommand cmd = CreateExecutionCommand (configuration, config); - if (context.ExecutionTarget != null) - cmd.Target = context.ExecutionTarget; + + var runConfig = runConfiguration as ProjectRunConfiguration; + if (runConfig == null) + return false; + + var asmRunConfig = runConfiguration as AssemblyRunConfiguration; + + ExecutionCommand executionCommand; + + if (asmRunConfig != null && asmRunConfig.StartAction == AssemblyRunConfiguration.StartActions.Program) { + executionCommand = Runtime.ProcessService.CreateCommand (asmRunConfig.StartProgram); + // If it is command for executing an assembly, add runtime options + var dcmd = executionCommand as DotNetExecutionCommand; + if (dcmd != null) { + string monoOptions; + asmRunConfig.MonoParameters.GenerateOptions (dcmd.EnvironmentVariables, out monoOptions); + dcmd.RuntimeArguments = monoOptions; + } + // If it is command for executing a process, add arguments, work directory and env vars + var pcmd = executionCommand as ProcessExecutionCommand; + if (pcmd != null) { + pcmd.Arguments = asmRunConfig.StartArguments; + pcmd.WorkingDirectory = asmRunConfig.StartWorkingDirectory; + + foreach (var env in asmRunConfig.EnvironmentVariables) + pcmd.EnvironmentVariables [env.Key] = env.Value; + } + } else { + executionCommand = CreateExecutionCommand (configuration, config, runConfig); + if (context.ExecutionTarget != null) + executionCommand.Target = context.ExecutionTarget; + } - return (compileTarget == CompileTarget.Exe || compileTarget == CompileTarget.WinExe) && context.ExecutionHandler.CanExecute (cmd); + return executionCommand != null && context.ExecutionHandler.CanExecute (executionCommand); } protected override ProjectFeatures OnGetSupportedFeatures () @@ -1142,12 +1219,31 @@ namespace MonoDevelop.Projects var sf = base.OnGetSupportedFeatures (); // Libraries are not executable by default, unless the project has a custom execution command - if (compileTarget == CompileTarget.Library && !Configurations.OfType<ProjectConfiguration> ().Any (c => c.CustomCommands.HasCommands (CustomCommandType.Execute))) + if (compileTarget == CompileTarget.Library + && !Configurations.OfType<ProjectConfiguration> ().Any (c => c.CustomCommands.HasCommands (CustomCommandType.Execute)) + && !GetRunConfigurations ().Any () + ) sf &= ~ProjectFeatures.Execute; return sf; } + protected override IEnumerable<SolutionItemRunConfiguration> OnGetRunConfigurations () + { + var configs = base.OnGetRunConfigurations (); + if (compileTarget == CompileTarget.Library) { + // A library project can't run by itself, so discard configurations which have "Project" as startup action + foreach (var c in configs) { + var dc = c as AssemblyRunConfiguration; + if (dc != null && (dc.StartAction == AssemblyRunConfiguration.StartActions.Project || string.IsNullOrEmpty (dc.StartProgram))) + continue; + yield return c; + } + } else + foreach (var c in configs) + yield return c; + } + protected override IEnumerable<FilePath> OnGetItemFiles (bool includeReferencedFiles) { var baseFiles = base.OnGetItemFiles (includeReferencedFiles); @@ -1505,7 +1601,7 @@ namespace MonoDevelop.Projects CheckReferenceChange (ei.FileName); } - protected async override Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) + protected async override Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) { DotNetProjectConfiguration dotNetProjectConfig = GetConfiguration (configuration) as DotNetProjectConfiguration; if (dotNetProjectConfig == null) { @@ -1515,7 +1611,7 @@ namespace MonoDevelop.Projects monitor.Log.WriteLine (GettextCatalog.GetString ("Running {0} ...", dotNetProjectConfig.CompiledOutputName)); - ExecutionCommand executionCommand = CreateExecutionCommand (configuration, dotNetProjectConfig); + ExecutionCommand executionCommand = CreateExecutionCommand (configuration, dotNetProjectConfig, runConfiguration as ProjectRunConfiguration); if (context.ExecutionTarget != null) executionCommand.Target = context.ExecutionTarget; @@ -1534,15 +1630,18 @@ namespace MonoDevelop.Projects protected virtual async Task OnExecuteCommand (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, ExecutionCommand executionCommand) { + bool externalConsole = false, pauseConsole = false; + var dotNetExecutionCommand = executionCommand as DotNetExecutionCommand; if (dotNetExecutionCommand != null) {
dotNetExecutionCommand.UserAssemblyPaths = GetUserAssemblyPaths (configuration); + externalConsole = dotNetExecutionCommand.ExternalConsole; + pauseConsole = dotNetExecutionCommand.PauseConsoleOutput; } - var dotNetProjectConfig = GetConfiguration (configuration) as DotNetProjectConfiguration; - var console = dotNetProjectConfig.ExternalConsole - ? context.ExternalConsoleFactory.CreateConsole (!dotNetProjectConfig.PauseConsoleOutput, monitor.CancellationToken) - : context.ConsoleFactory.CreateConsole (monitor.CancellationToken); + var console = externalConsole ? context.ExternalConsoleFactory.CreateConsole (!pauseConsole, monitor.CancellationToken) + : context.ConsoleFactory.CreateConsole (monitor.CancellationToken); + using (console) { ProcessAsyncOperation asyncOp = context.ExecutionHandler.Execute (executionCommand, console); @@ -1584,6 +1683,29 @@ namespace MonoDevelop.Projects TargetFramework = Runtime.SystemAssemblyService.GetTargetFramework (targetFx); } + internal override void ImportDefaultRunConfiguration (ProjectRunConfiguration config) + { + base.ImportDefaultRunConfiguration (config); + if (config is AssemblyRunConfiguration) { + var defaultConf = (DefaultConfiguration ?? Configurations.FirstOrDefault<SolutionItemConfiguration> ()) as DotNetProjectConfiguration; + if (defaultConf != null) { + var drc = (AssemblyRunConfiguration)config; + var cmd = defaultConf.CustomCommands.FirstOrDefault (cc => cc.Type == CustomCommandType.Execute); + if (cmd != null) { + drc.StartAction = AssemblyRunConfiguration.StartActions.Program; + drc.StartProgram = cmd.GetCommandFile (this, defaultConf.Selector); + drc.StartArguments = cmd.GetCommandArgs (this, defaultConf.Selector); + foreach (var v in cmd.EnvironmentVariables) + drc.EnvironmentVariables.Add (v.Key, v.Value); + drc.StartWorkingDirectory = cmd.GetCommandWorkingDir (this, defaultConf.Selector); + drc.ExternalConsole = cmd.ExternalConsole; + drc.PauseConsoleOutput = cmd.PauseExternalConsole; + defaultConf.CustomCommands.Remove (cmd); + } + } + } + } + protected override void OnWriteProjectHeader (ProgressMonitor monitor, MSBuildProject msproject) { base.OnWriteProjectHeader (monitor, msproject); @@ -1652,10 +1774,17 @@ namespace MonoDevelop.Projects return Project.OnGetReferencedAssemblyProjects (configuration); } +#pragma warning disable 672 // Member overrides obsolete member internal protected override ExecutionCommand OnCreateExecutionCommand (ConfigurationSelector configSel, DotNetProjectConfiguration configuration) { return Project.OnCreateExecutionCommand (configSel, configuration); } +#pragma warning restore 672 // Member overrides obsolete member + + internal protected override ExecutionCommand OnCreateExecutionCommand (ConfigurationSelector configSel, DotNetProjectConfiguration configuration, ProjectRunConfiguration runConfiguration) + { + return Project.OnCreateExecutionCommand (configSel, configuration, runConfiguration); + } internal protected override void OnReferenceRemovedFromProject (ProjectReferenceEventArgs e) { diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectExtension.cs index 51e5a24b4f..bdbf68ccef 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectExtension.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProjectExtension.cs @@ -82,11 +82,17 @@ namespace MonoDevelop.Projects return next.OnGetReferencedAssemblyProjects (configuration); } + [Obsolete("User overload that takes a RunConfiguration")] internal protected virtual ExecutionCommand OnCreateExecutionCommand (ConfigurationSelector configSel, DotNetProjectConfiguration configuration) { return next.OnCreateExecutionCommand (configSel, configuration); } + internal protected virtual ExecutionCommand OnCreateExecutionCommand (ConfigurationSelector configSel, DotNetProjectConfiguration configuration, ProjectRunConfiguration runConfiguration) + { + return next.OnCreateExecutionCommand (configSel, configuration, runConfiguration); + } + internal protected virtual void OnReferenceRemovedFromProject (ProjectReferenceEventArgs e) { next.OnReferenceRemovedFromProject (e); diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/EnvironmentVariableCollection.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/EnvironmentVariableCollection.cs new file mode 100644 index 0000000000..63f0fcd6a4 --- /dev/null +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/EnvironmentVariableCollection.cs @@ -0,0 +1,189 @@ +// +// EnvironmentVariableCollection.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 MonoDevelop.Core.Serialization; +using System.Linq; +using System.Collections.Generic; +using System.Collections; + +namespace MonoDevelop.Projects +{ + public class EnvironmentVariableCollection: ICustomDataItem, IDictionary<string,string> + { + List<KeyValuePair<string, string>> dict; + + public EnvironmentVariableCollection () + { + dict = new List<KeyValuePair<string, string>> (); + } + + public EnvironmentVariableCollection (IDictionary<string,string> dictionary) + { + dict = dictionary.ToList (); + } + + void ICustomDataItem.Deserialize (ITypeSerializer handler, DataCollection data) + { + foreach (var v in data.OfType<DataItem> ()) { + var name = v.ItemData ["name"] as DataValue; + var value = v.ItemData ["value"] as DataValue; + if (name != null && value != null) + this [name.Value] = value.Value; + } + } + + DataCollection ICustomDataItem.Serialize (ITypeSerializer handler) + { + // Add known keys first, then new keys + var col = new DataCollection (); + foreach (var ev in dict) { + var vi = new DataItem (); + vi.Name = "Variable"; + vi.ItemData.Add (new DataValue ("name", ev.Key) { StoreAsAttribute = true }); + vi.ItemData.Add (new DataValue ("value", ev.Value) { StoreAsAttribute = true }); + col.Add (vi); + } + return col; + } + + public string this [string key] { + get { + for (int n = 0; n < dict.Count; n++) + if (dict [n].Key == key) + return dict [n].Value; + throw new KeyNotFoundException (); + } + set { + for (int n = 0; n < dict.Count; n++) { + if (dict [n].Key == key) { + dict [n] = new KeyValuePair<string, string> (key, value); + return; + } + } + dict.Add (new KeyValuePair<string, string> (key, value)); + } + } + + public int Count { + get { + return dict.Count; + } + } + + bool ICollection<KeyValuePair<string, string>>.IsReadOnly { + get { + return false; + } + } + + public ICollection<string> Keys { + get { + return dict.Select (ev => ev.Key).ToList (); + } + } + + public ICollection<string> Values { + get { + return dict.Select (ev => ev.Value).ToList (); + } + } + + void ICollection<KeyValuePair<string, string>>.Add (KeyValuePair<string, string> item) + { + dict.Add (item); + } + + public void Add (string key, string value) + { + dict.Add (new KeyValuePair<string, string> (key, value)); + } + + public void Clear () + { + dict.Clear (); + } + + bool ICollection<KeyValuePair<string, string>>.Contains (KeyValuePair<string, string> item) + { + return dict.Any (ev => ev.Key == item.Key && ev.Value == item.Value); + } + + public bool ContainsKey (string key) + { + return FindKey (key) != -1; + } + + void ICollection<KeyValuePair<string, string>>.CopyTo (KeyValuePair<string, string> [] array, int arrayIndex) + { + ((ICollection<KeyValuePair<string, string>>)dict).CopyTo (array, arrayIndex); + } + + IEnumerator IEnumerable.GetEnumerator () + { + return ((IEnumerable)dict).GetEnumerator (); + } + + IEnumerator<KeyValuePair<string, string>> IEnumerable<KeyValuePair<string, string>>.GetEnumerator () + { + return ((IEnumerable<KeyValuePair<string, string>>)dict).GetEnumerator (); + } + + bool ICollection<KeyValuePair<string, string>>.Remove (KeyValuePair<string, string> item) + { + return dict.RemoveAll (ev => ev.Key == item.Key && ev.Value == item.Value) > 0; + } + + public bool Remove (string key) + { + var i = FindKey (key); + if (i != -1) { + dict.RemoveAt (i); + return true; + } + return false; + } + + bool IDictionary<string, string>.TryGetValue (string key, out string value) + { + var i = FindKey (key); + if (i != -1) { + value = dict [i].Value; + return true; + } + value = null; + return false; + } + + int FindKey (string key) + { + for (int n = 0; n < dict.Count; n++) + if (dict [n].Key == key) + return n; + return -1; + } + } +} + diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ExecutionContext.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ExecutionContext.cs index ae1334fe5f..1ec0889b12 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ExecutionContext.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ExecutionContext.cs @@ -69,5 +69,7 @@ namespace MonoDevelop.Projects public ExternalConsoleFactory ExternalConsoleFactory { get { return MonoDevelop.Core.Execution.ExternalConsoleFactory.Instance; } } + + internal object RunConfiguration { get; set; } } } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IRunTarget.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IRunTarget.cs new file mode 100644 index 0000000000..d2e0172dd5 --- /dev/null +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/IRunTarget.cs @@ -0,0 +1,83 @@ +// +// IRunTarget.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.Collections.Generic; +using MonoDevelop.Core; +using System.Threading.Tasks; +using System; +using MonoDevelop.Core.Execution; + +namespace MonoDevelop.Projects +{ + public interface IRunTarget + { + /// <summary> + /// Executes the target + /// </summary> + /// <param name="monitor">Monitor for tracking progress</param> + /// <param name="context">Execution context</param> + /// <param name="configuration">Configuration to execute</param> + /// <param name="runConfiguration">Run configuration to use</param> + Task Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, RunConfiguration runConfiguration); + + /// <summary> + /// Determines whether this target can be executed using the specified execution context and configuration. + /// </summary> + /// <returns><c>true</c> if this instance can be executed; otherwise, <c>false</c>.</returns> + /// <param name="context">An execution context</param> + /// <param name="configuration">Configuration to execute</param> + /// <param name="runConfiguration">Run configuration to use</param> + bool CanExecute (ExecutionContext context, ConfigurationSelector configuration, RunConfiguration runConfiguration); + + /// <summary> + /// Prepares the target for execution + /// </summary> + /// <returns>The execution.</returns> + /// <param name="monitor">Monitor for tracking progress</param> + /// <param name="context">Execution context</param> + /// <param name="configuration">Configuration to execute</param> + /// <param name="runConfiguration">Run configuration to use</param> + /// <remarks>This method can be called (it is not mandatory) before Execute() to give the target a chance + /// to asynchronously prepare the execution that is going to be done later on. It can be used for example + /// to start the simulator that is going to be used for execution. Calling this method is optional, and + /// there is no guarantee that Execute() will actually be called.</remarks> + Task PrepareExecution (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, RunConfiguration runConfiguration); + + /// <summary> + /// Gets the run configurations that can be used to execute this item + /// </summary> + /// <returns>The run configurations.</returns> + IEnumerable<RunConfiguration> GetRunConfigurations (); + + /// <summary> + /// Gets the execution targets available for this item + /// </summary> + /// <returns>The execution targets.</returns> + /// <param name="configuration">Configuration to execute</param> + /// <param name="runConfiguration">Run configuration to use</param> + IEnumerable<ExecutionTarget> GetExecutionTargets (ConfigurationSelector configuration, RunConfiguration runConfiguration); + } +} diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/MonoExecutionParameters.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/MonoExecutionParameters.cs new file mode 100644 index 0000000000..321d694c14 --- /dev/null +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/MonoExecutionParameters.cs @@ -0,0 +1,560 @@ +// +// AdvancedMonoParameters.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.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.ComponentModel; +using MonoDevelop.Core; +using MonoDevelop.Core.Serialization; +using System.Text; + + +namespace MonoDevelop.Projects +{ + public sealed class MonoExecutionParameters + { + class EnvVarAttribute : Attribute + { + public string Name; + public string TrueValue = string.Empty; + + public EnvVarAttribute (string name) + { + this.Name = name; + } + + public EnvVarAttribute (string name, string trueValue) + { + this.Name = name; + this.TrueValue = trueValue; + } + } + + class MonoArgAttribute : Attribute + { + public string Name; + + public MonoArgAttribute (string name) + { + Name = name; + } + } + + public enum LogLevel + { + [MonoArg (null)] + [LocalizedDescription ("Default")] + Default, + [MonoArg ("error")] + Error, + [MonoArg ("critical")] + Critical, + [MonoArg ("warning")] + Warning, + [MonoArg ("message")] + Message, + [MonoArg ("info")] + Info, + [MonoArg ("debug")] + Debug + } + + [Flags] + public enum LogMask + { + [MonoArg (null)] + None = 0, + [MonoArg ("asm")] + AssemblyLoader = 0x01, + [MonoArg ("type")] + Type = 0x02, + [MonoArg ("dll")] + NativeLibraryLoader = 0x04, + [MonoArg ("cfg")] + ConfigFileLoader = 0x08, + [MonoArg ("gc")] + GarbageCollector = 0x10, + [MonoArg ("aot")] + Aot = 0x20, + [MonoArg ("all")] + All = 0xff + } + + public enum SecurityMode + { + [MonoArg (null)] + [LocalizedDescription ("Disabled")] + Disabled, + [MonoArg ("cas")] + Cas, + [MonoArg ("core-clr")] + CoreClr, + [MonoArg ("verifiable")] + Verifiable, + [MonoArg ("validil")] + ValidIL + } + + public enum GcType + { + [MonoArg (null)] + [LocalizedDescription ("Default")] + Default, + [MonoArg ("boehm")] + Boehm, + [MonoArg ("sgen")] + SGen + } + + public MonoExecutionParameters () + { + foreach (PropertyInfo prop in GetType ().GetProperties ()) { + ItemPropertyAttribute propAttr = (ItemPropertyAttribute) Attribute.GetCustomAttribute (prop, typeof(ItemPropertyAttribute)); + if (propAttr != null) { + if (propAttr.DefaultValue != null) + prop.SetValue (this, propAttr.DefaultValue, null); + } + } + } + + public void GenerateOptions (IDictionary<string,string> envVars, out string options) + { + StringBuilder ops = new StringBuilder (); + if (MonoStripDriveLetters || MonoCaseInsensitivePaths) { + if (MonoStripDriveLetters && MonoCaseInsensitivePaths) + envVars ["MONO_IOMAP"] = "all"; + else if (MonoStripDriveLetters) + envVars ["MONO_IOMAP"] = "drive"; + else if (MonoCaseInsensitivePaths) + envVars ["MONO_IOMAP"] = "case"; + } + for (int n=0; n< MonoVerboseLevel; n++) + ops.Append ("-v "); + + if (MonoDebugMode || MonoDebugMdbOptimizations || MonoDebugCasts || MonoGdbInfo) { + ops.Append ("--debug="); + if (MonoDebugMdbOptimizations) + ops.Append ("mdb-optimizations,"); + if (MonoDebugCasts) + ops.Append ("casts,"); + if (MonoGdbInfo) + ops.Append ("gdb,"); + ops.Remove (ops.Length - 1, 1); + ops.Append (' '); + } + + foreach (PropertyInfo prop in GetType ().GetProperties ()) { + MonoArgAttribute argAttr = (MonoArgAttribute) Attribute.GetCustomAttribute (prop, typeof(MonoArgAttribute)); + if (argAttr != null) { + object val = GetValue (prop.GetValue (this, null)); + if ((val is bool) && (bool)val) + ops.Append (argAttr.Name).Append (' '); + else if ((val is string) && !string.IsNullOrEmpty ((string)val)) + ops.AppendFormat (argAttr.Name, val).Append (' '); + } else { + EnvVarAttribute envVar = (EnvVarAttribute) Attribute.GetCustomAttribute (prop, typeof(EnvVarAttribute)); + if (envVar != null) { + object val = GetValue (prop.GetValue (this, null)); + if ((val is bool) && (bool)val) + envVars [envVar.Name] = envVar.TrueValue; + else if ((val is string) && !string.IsNullOrEmpty ((string)val)) + envVars [envVar.Name] = val.ToString (); + } + } + } + options = ops.ToString ().Trim (); + } + + object GetValue (object val) + { + if (val.GetType ().IsEnum) { + long ival = Convert.ToInt64 (val); + Type etype = val.GetType (); + bool isFlags = val.GetType ().IsDefined (typeof(FlagsAttribute), false); + string flags = ""; + IList names = Enum.GetNames (etype); + foreach (FieldInfo f in val.GetType ().GetFields ()) { + if (!names.Contains (f.Name)) + continue; + long v = Convert.ToInt64 (Enum.Parse (val.GetType(), f.Name)); + MonoArgAttribute attr = (MonoArgAttribute) Attribute.GetCustomAttribute (f, typeof(MonoArgAttribute)); + string sval = attr != null ? attr.Name : f.Name; + if (ival == v) { + return sval; + } + else if (isFlags && (v & ival) != 0) { + if (flags.Length > 0) + flags += ","; + flags += sval; + } + } + if (isFlags) + return flags; + } + return val; + } + + public string GenerateDescription () + { + StringBuilder ops = new StringBuilder (); + + foreach (PropertyInfo prop in GetType ().GetProperties ()) { + ItemPropertyAttribute propAttr = (ItemPropertyAttribute)Attribute.GetCustomAttribute (prop, typeof (ItemPropertyAttribute)); + var pval = prop.GetValue (this, null); + if (object.Equals (pval, propAttr.DefaultValue)) + continue; + if (ops.Length > 0) + ops.Append (", "); + var nameAttr = (LocalizedDisplayNameAttribute)Attribute.GetCustomAttribute (prop, typeof (LocalizedDisplayNameAttribute)); + ops.Append (nameAttr.DisplayName); + if (!(pval is bool)) + ops.Append (": " + GetValue (pval)); + } + return ops.ToString (); + } + public MonoExecutionParameters Clone () + { + return (MonoExecutionParameters) MemberwiseClone (); + } + + [LocalizedCategory ("Debug")] + [LocalizedDisplayName ("Debug Mode")] + [LocalizedDescription ("Enable debugging support.")] + [ItemProperty (DefaultValue=false)] + public bool MonoDebugMode { get; set; } + + [LocalizedCategory ("Debug")] + [LocalizedDisplayName ("Debug Casts")] + [LocalizedDescription ("Enable more detailed InvalidCastException messages.")] + [ItemProperty (DefaultValue=false)] + public bool MonoDebugCasts { get; set; } + + [LocalizedCategory ("Debug")] + [LocalizedDisplayName ("MDB Mode")] + [LocalizedDescription ("Disable some JIT optimizations which are normally " + + "disabled when running inside the debugger. This is useful " + + "if you plan to attach to the running process with the debugger.")] + [ItemProperty (DefaultValue=false)] + public bool MonoDebugMdbOptimizations { get; set; } + + [LocalizedCategory ("Debug")] + [LocalizedDisplayName ("GDB Symbols")] + [LocalizedDescription ("Generate and register debugging information with gdb. " + + "This is only supported on some platforms, and only when " + + "using gdb 7.0 or later.")] + [ItemProperty (DefaultValue=false)] + public bool MonoGdbInfo { get; set; } + + [LocalizedCategory ("Runtime")] + [LocalizedDisplayName ("Profiler")] + [LocalizedDescription ("Runs in profiling mode with the specified profiler module.")] + [ItemProperty (DefaultValue="")] + [MonoArg ("--profile={0}")] + public string MonoProfile { get; set; } + + [LocalizedCategory ("Debug")] + [LocalizedDisplayName ("Verbose Level")] + [LocalizedDescription ("Increases the verbosity level.")] + [ItemProperty (DefaultValue=0)] + public int MonoVerboseLevel { get; set; } + + [LocalizedCategory ("Runtime")] + [LocalizedDisplayName ("Runtime Version")] + [LocalizedDescription ("Use the specified runtime version, instead of autodetecting")] + [ItemProperty (DefaultValue="")] + [MonoArg ("--runtime={0}")] + public string MonoRuntimeVersion { get; set; } + + [LocalizedCategory ("Security")] + [LocalizedDisplayName ("Security Mode")] + [LocalizedDescription ("Turns on the unsupported security manager (off by default).")] + [MonoArg ("--security={0}")] + [ItemProperty (DefaultValue=SecurityMode.Disabled)] + public SecurityMode MonoSecurityMode { get; set; } + + [LocalizedCategory ("Security")] + [LocalizedDisplayName ("Verify All")] + [LocalizedDescription ("Verifies mscorlib and assemblies in the global assembly cache " + + "for valid IL, and all user code for IL verifiability.")] + [MonoArg ("--verifyAll")] + [ItemProperty (DefaultValue=false)] + public bool MonoVerifyAll { get; set; } + + [LocalizedCategory ("Tracing")] + [LocalizedDisplayName ("Trace Expression")] + [LocalizedDescription ("Comma separated list of expressions to trace. " + + "'all' all assemlies, " + + "'none' no assemblies, " + + "'program' entry point assembly, " + + "'assembly' specifies an assembly, " + + "'T:Type' specifies a type, " + + "'M:Type:Method' a method, " + + "'N:Namespace' a namespace. " + + "'disabled' don't print any output until toggled via SIGUSR2. " + + "Prefix with '-' to exclude and expression.")] + [MonoArg ("--trace={0}")] + [ItemProperty (DefaultValue="")] + public string MonoTraceExpressions { get; set; } + + [LocalizedCategory ("Logging")] + [LocalizedDisplayName ("Log Level")] + [LocalizedDescription ("Possible values are 'error', 'critical', 'warning', " + + "'message', 'info', 'debug'. The default value is 'error'. " + + "Messages with a logging level greater then or equal to the log level " + + "will be printed to stdout/stderr.")] + [EnvVar ("MONO_LOG_LEVEL")] + [ItemProperty (DefaultValue=LogLevel.Default)] + public LogLevel MonoLogLevel { get; set; } + + [LocalizedCategory ("Logging")] + [LocalizedDisplayName ("Log Mask")] + [LocalizedDescription ("Possible values are 'asm' (assembly loader), 'type'," + + " 'dll' (native library loader), 'gc' (garbage collector), " + + "'cfg' (config file loader), 'aot' (precompiler) and 'all'. " + + "The default value is 'all'. Changing the mask value allows you " + + "to display only messages for a certain component. You can use " + + "multiple masks by comma separating them. For example to see " + + "config file messages and assembly loader messages set you mask " + + "to 'asm,cfg'.")] + [EnvVar ("MONO_LOG_MASK")] + [ItemProperty (DefaultValue=LogMask.None)] + public LogMask MonoLogMask { get; set; } + + [LocalizedCategory ("Library Options")] + [LocalizedDisplayName ("Serializer Generation")] + [LocalizedDescription ("The possible values are `no' to disable the use of a C# customized " + + "serializer, or an integer that is the minimum number of uses before the " + + "runtime will produce a custom serializer (0 will produce a custom " + + "serializer on the first access, 50 will produce a serializer on the 50th " + + "use). Mono will fallback to an interpreted serializer if the serializer " + + "generation somehow fails. This behavior can be disabled by setting the " + + "option `nofallback' (for example: '0,nofallback').")] + [EnvVar ("MONO_XMLSERIALIZER_THS")] + [ItemProperty (DefaultValue="")] + public string MonoXmlSerializerGeneration { get; set; } + + [LocalizedCategory ("Configuration")] + [LocalizedDisplayName ("Mono Configuration Directory")] + [LocalizedDescription ("Overrides the default system configuration directory ($PREFIX/etc). " + + "It's used to locate machine.config file.")] + [EnvVar ("MONO_CFG_DIR")] + [ItemProperty (DefaultValue="")] + public string MonoConfigDir { get; set; } + + [LocalizedCategory ("Configuration")] + [LocalizedDisplayName ("Mono Configuration File")] + [LocalizedDescription ("Overrides the default runtime configuration file ($PREFIX/etc/mono/config).")] + [MonoArg ("--config {0}")] + [ItemProperty (DefaultValue="")] + public string MonoConfigFile { get; set; } + + [LocalizedCategory ("Runtime")] + [LocalizedDisplayName ("Disable AIO")] + [LocalizedDescription ("If set, tells mono NOT to attempt using native asynchronous I/O " + + "services. In that case, a default select/poll implementation is " + + "used. Currently only epoll() is supported.")] + [EnvVar ("MONO_DISABLE_AIO")] + [ItemProperty (DefaultValue=false)] + public bool MonoDisableAIO { get; set; } + + [LocalizedCategory ("Library Options")] + [LocalizedDisplayName ("Disable Managed Collation")] + [LocalizedDescription ("If set, the runtime uses unmanaged collation (which actually " + + "means no culture-sensitive collation). It internally disables " + + "managed collation functionality invoked via the members of " + + "System.Globalization.CompareInfo class.")] + [EnvVar ("MONO_DISABLE_MANAGED_COLLATION", "yes")] + [ItemProperty (DefaultValue=false)] + public bool MonoDisableManagedCollation { get; set; } + + [LocalizedCategory ("Library Options")] + [LocalizedDisplayName ("External Encodings")] + [LocalizedDescription ("A colon-separated list of text encodings to try when turning " + + "externally-generated text (e.g. command-line arguments or " + + "filenames) into Unicode.")] + [EnvVar ("MONO_EXTERNAL_ENCODINGS")] + [ItemProperty (DefaultValue="")] + public string MonoExternalEncodings { get; set; } + + [LocalizedCategory ("Configuration")] + [LocalizedDisplayName ("GAC Prefix")] + [LocalizedDescription ("Provides a prefix the runtime uses to look for Global Assembly " + + "Caches. Directories are separated by the platform path separator " + + "(colons on unix). MONO_GAC_PREFIX should point to the top " + + "directory of a prefixed install. Or to the directory provided in " + + "the gacutil /gacdir command. Example: /home/username/.mono:/usr/local/mono/")] + [EnvVar ("MONO_GAC_PREFIX")] + [ItemProperty (DefaultValue="")] + public string MonoGacPrefix { get; set; } + + [LocalizedCategory ("Compatibility")] + [LocalizedDisplayName ("Strip Drive Letters")] + [LocalizedDescription ("When enabled, Mono removes the drive letter from Windows paths.")] + [ItemProperty (DefaultValue=false)] + public bool MonoStripDriveLetters { get; set; } + + [LocalizedCategory ("Compatibility")] + [LocalizedDisplayName ("Case Insensitive Paths")] + [LocalizedDescription ("When enabled, Mono does case-insensitive file matching in every directory in a path.")] + [ItemProperty (DefaultValue=false)] + public bool MonoCaseInsensitivePaths { get; set; } + + [LocalizedCategory ("Library Options")] + [LocalizedDisplayName ("Managed Watcher")] + [LocalizedDescription ("When set, System.IO.FileSystemWatcher will use the default managed " + + "implementation (slow).")] + [EnvVar ("MONO_MANAGED_WATCHER", "yes")] + [ItemProperty (DefaultValue=false)] + public bool MonoManagedWatcher { get; set; } + + [LocalizedCategory ("Runtime")] + [LocalizedDisplayName ("No SMP")] + [LocalizedDescription ("If set, causes the mono process to be bound to a single processor. " + + "This may be useful when debugging or working around race conditions.")] + [EnvVar ("MONO_NO_SMP")] + [ItemProperty (DefaultValue=false)] + public bool MonoNoSmp { get; set; } + + [LocalizedCategory ("Configuration")] + [LocalizedDisplayName ("Mono Path")] + [LocalizedDescription ("Provides a search path to the runtime where to look for library " + + "files. This is a tool convenient for debugging applications, " + + "but should not be used by deployed applications as it breaks the " + + "assembly loader in subtle ways. Directories are separated by " + + "the platform path separator (colons on unix). Example: " + + "/home/username/lib:/usr/local/mono/lib")] + [EnvVar ("MONO_PATH")] + [ItemProperty (DefaultValue="")] + public string MonoPath { get; set; } + + [LocalizedCategory ("Library Options")] + [LocalizedDisplayName ("Windows Forms Theme")] + [LocalizedDescription ("The name of the theme to be used by Windows.Forms. Available " + + "themes include 'clearlooks', 'nice' and 'win32'. The default is 'win32'")] + [EnvVar ("MONO_THEME")] + [ItemProperty (DefaultValue="")] + public string MonoWindowsFormsTheme { get; set; } + + [LocalizedCategory ("Runtime")] + [LocalizedDisplayName ("Threads Per Cpu")] + [LocalizedDescription ("The maximum number of threads in the general threadpool will be " + + "20 + (ThreadsPerCpu * number of CPUs). The default value" + + "for this variable is 10.")] + [EnvVar ("MONO_THREADS_PER_CPU")] + [ItemProperty (DefaultValue="")] + public string MonoThreadsPerCpu { get; set; } + + [LocalizedCategory ("Library Options")] + [LocalizedDisplayName ("Keep ASP.NET Temporary Files")] + [LocalizedDescription ("If set, temporary source files generated by ASP.NET support " + + "classes will not be removed. They will be kept in the " + + "user's temporary directory.")] + [EnvVar ("MONO_ASPNET_NODELETE")] + [ItemProperty (DefaultValue=false)] + public bool MonoAspNetNoDelete { get; set; } + + [LocalizedCategory ("Tracing")] + [LocalizedDisplayName ("Trace Listener")] + [LocalizedDescription ("If set, enables the System.Diagnostics.DefaultTraceListener, " + + "which will print the output of the System.Diagnostics Trace and " + + "Debug classes. It can be set to a filename, and to Console.Out " + + "or Console.Error to display output to standard output or standard " + + "error, respectively. If it's set to Console.Out or Console.Error " + + "you can append an optional prefix that will be used when writing " + + "messages like this: Console.Error:MyProgramName.")] + [EnvVar ("MONO_TRACE_LISTENER")] + [ItemProperty (DefaultValue="")] + public string MonoTraceListener { get; set; } + + [LocalizedCategory ("Runtime")] + [LocalizedDisplayName ("X11 Exceptions")] + [LocalizedDescription ("If set, an exception is thrown when a X11 error is encountered. " + + "By default a message is displayed but execution continues.")] + [EnvVar ("MONO_XEXCEPTIONS")] + [ItemProperty (DefaultValue=false)] + public bool MonoXExceptions { get; set; } + + [LocalizedCategory ("Debug")] + [LocalizedDisplayName ("XDebug")] + [LocalizedDescription ("When the the MONO_XDEBUG env var is set, debugging info for JITted " + + "code is emitted into a shared library, loadable into gdb. " + + "This enables, for example, to see managed frame names on gdb backtraces.")] + [EnvVar ("MONO_XDEBUG")] + [ItemProperty (DefaultValue=false)] + public bool MonoXDebug { get; set; } + + [LocalizedCategory ("Runtime")] + [LocalizedDisplayName ("Garbage Collector")] + [LocalizedDescription ("Selects the Garbage Collector engine for Mono to use.")] + [MonoArg ("--gc={0}")] + [ItemProperty (DefaultValue=GcType.Default)] + public GcType MonoGcType { get; set; } + + [LocalizedCategory ("LLVM")] + [LocalizedDisplayName ("Enable LLVM")] + [LocalizedDescription ("If the Mono runtime has been compiled with LLVM support (not " + + "available in all configurations), this option enables use the LLVM optimization " + + "and code generation engine to JIT or AOT compile. For more information " + + "consult: http://www.mono-project.com/Mono_LLVM")] + [MonoArg ("--llvm")] + [ItemProperty (DefaultValue=false)] + public bool MonoLlvm { get; set; } + + [LocalizedCategory ("LLVM")] + [LocalizedDisplayName ("Disable LLVM")] + [LocalizedDescription ("When using a Mono that has been compiled with LLVM support, it " + + "forces Mono to fallback to its JIT engine and not use the LLVM backend")] + [MonoArg ("--nollvm")] + [ItemProperty (DefaultValue=false)] + public bool MonoNoLlvm { get; set; } + + [LocalizedCategory ("Optimizations")] + [LocalizedDisplayName ("Desktop Mode")] + [LocalizedDescription ("Configures the virtual machine to be better suited for desktop " + + "applications. Currently this sets the GC system to avoid " + + "expanding the heap as much as possible at the expense of slowing " + + "down garbage collection a bit.")] + [MonoArg ("--desktop")] + [ItemProperty (DefaultValue=false)] + public bool MonoDesktopMode { get; set; } + + [LocalizedCategory ("Optimizations")] + [LocalizedDisplayName ("Server Mode")] + [LocalizedDescription ("Configures the virtual machine to be better suited for server operations.")] + [MonoArg ("--server")] + [ItemProperty (DefaultValue=false)] + public bool MonoServerMode { get; set; } + + [LocalizedCategory ("Additional Options")] + [LocalizedDisplayName ("Additional Options")] + [LocalizedDescription ("Additional command line options to be provided to the Mono command.")] + [MonoArg ("{0}")] + [ItemProperty (DefaultValue="")] + public string MonoAdditionalOptions { get; set; } + } +} diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/CustomRuntimeExecutionModeSet.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/MultiItemSolutionRunConfiguration.cs index 830bd492b3..99b88483df 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/CustomRuntimeExecutionModeSet.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/MultiItemSolutionRunConfiguration.cs @@ -1,21 +1,21 @@ -// -// CustomRuntimeExecutionModeSet.cs -// +// +// MultiItemSolutionRunConfiguration.cs +// // Author: -// Lluis Sanchez Gual <lluis@novell.com> -// -// Copyright (c) 2009 Novell, Inc (http://www.novell.com) -// +// 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 @@ -23,30 +23,19 @@ // 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; -using MonoDevelop.Core.Assemblies; -namespace MonoDevelop.Core.Assemblies +namespace MonoDevelop.Projects { - public class CustomRuntimeExecutionModeSet: IExecutionModeSet + class MultiItemSolutionRunConfiguration: SolutionRunConfiguration { - #region IExecutionModeSet implementation - public string Name { - get { - return "Custom Runtime"; - } - } - - public IEnumerable<IExecutionMode> ExecutionModes { - get { - foreach (TargetRuntime tr in Runtime.SystemAssemblyService.GetTargetRuntimes ()) { - yield return new ExecutionMode (tr.Id, tr.DisplayName, tr.GetExecutionHandler ()); - } - } + public MultiItemSolutionRunConfiguration (string id, string name): base (id, name) + { + Items = new List<SolutionItem> (); } - #endregion + + public List<SolutionItem> Items { get; set; } } } + diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProcessRunConfiguration.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProcessRunConfiguration.cs new file mode 100644 index 0000000000..70967baf7d --- /dev/null +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProcessRunConfiguration.cs @@ -0,0 +1,88 @@ +// +// ProcessRunConfiguration.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.Linq; +using MonoDevelop.Core; +using MonoDevelop.Core.Serialization; + +namespace MonoDevelop.Projects +{ + public class ProcessRunConfiguration: ProjectRunConfiguration + { + public ProcessRunConfiguration (string name): base (name) + { + } + + [ItemProperty (DefaultValue = "")] + public string StartArguments { get; set; } = ""; + + [ItemProperty (DefaultValue = "")] + public FilePath StartWorkingDirectory { get; set; } = ""; + + [ItemProperty ("ConsolePause", DefaultValue = true)] + public bool PauseConsoleOutput { get; set; } = true; + + [ItemProperty (DefaultValue = false)] + public bool ExternalConsole { get; set; } = false; + + [ItemProperty (SkipEmpty = true, WrapObject = false)] + public EnvironmentVariableCollection EnvironmentVariables { get; private set; } = new EnvironmentVariableCollection (); + + public override string Summary { + get { + string envVars = null; + if (EnvironmentVariables.Count > 0) { + var v = EnvironmentVariables.First (); + envVars = v.Key + "=" + v.Value; + if (EnvironmentVariables.Count > 1) + envVars += "..."; + } + if (!string.IsNullOrEmpty (StartArguments) && envVars != null) + return GettextCatalog.GetString ("Run with arguments '{0}' and environment variables '{1}'", StartArguments, envVars); + else if (!string.IsNullOrEmpty (StartArguments)) + return GettextCatalog.GetString ("Run with arguments '{0}'", StartArguments); + else if (envVars != null) + return GettextCatalog.GetString ("Run with environment variables '{0}''", envVars); + else + return GettextCatalog.GetString ("Run with no additional arguments"); + } + } + + protected override void OnCopyFrom (ProjectRunConfiguration config, bool isRename) + { + base.OnCopyFrom (config, isRename); + + var other = (ProcessRunConfiguration)config; + + StartArguments = other.StartArguments; + StartWorkingDirectory = other.StartWorkingDirectory; + EnvironmentVariables = new EnvironmentVariableCollection (other.EnvironmentVariables); + ExternalConsole = other.ExternalConsole; + PauseConsoleOutput = other.PauseConsoleOutput; + } + } +} + diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs index 662a47f01f..b42f62272f 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs @@ -61,12 +61,15 @@ namespace MonoDevelop.Projects string[] buildActions; MSBuildProject sourceProject; + MSBuildProject userProject; string productVersion; string schemaVersion; bool modifiedInMemory; bool msbuildUpdatePending; ProjectExtension projectExtension; + RunConfigurationCollection runConfigurations; + bool defaultRunConfigurationCreated; List<string> defaultImports; @@ -76,6 +79,7 @@ namespace MonoDevelop.Projects protected Project () { + runConfigurations = new RunConfigurationCollection (this); items = new ProjectItemCollection (this); FileService.FileChanged += HandleFileChanged; Runtime.SystemAssemblyService.DefaultRuntimeChanged += OnDefaultRuntimeChanged; @@ -88,6 +92,13 @@ namespace MonoDevelop.Projects get { return items; } } + public RunConfigurationCollection RunConfigurations { + get { + CreateDefaultConfiguration (); + return runConfigurations; + } + } + protected Project (params string[] flavorGuids): this() { this.flavorGuids = flavorGuids; @@ -289,6 +300,75 @@ namespace MonoDevelop.Projects base.OnConfigurationRemoved (args); } + protected override void OnItemReady () + { + base.OnItemReady (); + } + + internal virtual void ImportDefaultRunConfiguration (ProjectRunConfiguration config) + { + } + + public ProjectRunConfiguration CreateRunConfiguration (string name) + { + var c = CreateRunConfigurationInternal (name); + + // When creating a ProcessRunConfiguration, set the value of ExternalConsole and PauseConsoleOutput from the default configuration + var pc = c as ProcessRunConfiguration; + if (pc != null) { + var dc = RunConfigurations.FirstOrDefault (rc => rc.IsDefaultConfiguration) as ProcessRunConfiguration; + if (dc != null) { + pc.ExternalConsole = dc.ExternalConsole; + pc.PauseConsoleOutput = dc.PauseConsoleOutput; + } + } + return c; + } + + ProjectRunConfiguration CreateRunConfigurationInternal (string name) + { + var c = CreateUninitializedRunConfiguration (name); + c.Initialize (this); + return c; + } + + public ProjectRunConfiguration CreateUninitializedRunConfiguration (string name) + { + return ProjectExtension.OnCreateRunConfiguration (name); + } + + public ProjectRunConfiguration CloneRunConfiguration (ProjectRunConfiguration runConfig) + { + var clone = CreateUninitializedRunConfiguration (runConfig.Name); + clone.CopyFrom (runConfig, false); + return clone; + } + + public ProjectRunConfiguration CloneRunConfiguration (ProjectRunConfiguration runConfig, string newName) + { + var clone = CreateUninitializedRunConfiguration (newName); + clone.CopyFrom (runConfig, true); + return clone; + } + + void CreateDefaultConfiguration () + { + // If the project doesn't have a Default run configuration, create one + if (!defaultRunConfigurationCreated) { + defaultRunConfigurationCreated = true; + if (!runConfigurations.Any (c => c.IsDefaultConfiguration)) { + var rc = CreateRunConfigurationInternal ("Default"); + ImportDefaultRunConfiguration (rc); + runConfigurations.Insert (0, rc); + } + } + } + + protected override IEnumerable<SolutionItemRunConfiguration> OnGetRunConfigurations () + { + return RunConfigurations; + } + protected virtual void OnGetDefaultImports (List<string> imports) { } @@ -531,6 +611,13 @@ namespace MonoDevelop.Projects // Doesn't save the file to disk if the content did not change if (await sourceProject.SaveAsync (FileName)) { + if (userProject != null) { + if (!userProject.GetAllObjects ().Any ()) + File.Delete (userProject.FileName); + else + await userProject.SaveAsync (userProject.FileName); + } + var pb = GetCachedProjectBuilder (); if (pb != null) { try { @@ -1744,7 +1831,7 @@ namespace MonoDevelop.Projects return Task.FromResult (BuildResult.CreateSuccess ()); } - protected override Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) + protected override Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) { ProjectConfiguration config = GetConfiguration (configuration) as ProjectConfiguration; if (config == null) @@ -2022,6 +2109,10 @@ namespace MonoDevelop.Projects void ReadProject (ProgressMonitor monitor, MSBuildProject msproject) { + if (File.Exists (msproject.FileName + ".user")) { + userProject = new MSBuildProject (msproject.EngineManager); + userProject.Load (msproject.FileName + ".user"); + } ProjectExtension.OnReadProjectHeader (monitor, msproject); modifiedInMemory = false; msbuildUpdatePending = false; @@ -2068,6 +2159,8 @@ namespace MonoDevelop.Projects InitMainGroupProperties (globalGroup); foreach (ProjectConfiguration conf in Configurations) InitConfiguration (conf); + foreach (var es in runConfigurations) + InitRunConfiguration ((ProjectRunConfiguration)es); } sourceProject.IsNewProject = false; @@ -2080,7 +2173,7 @@ namespace MonoDevelop.Projects class ConfigData { - public ConfigData (string conf, string plt, IMSBuildPropertySet grp) + public ConfigData (string conf, string plt, MSBuildPropertyGroup grp) { Config = conf; Platform = plt; @@ -2089,7 +2182,7 @@ namespace MonoDevelop.Projects public string Config; public string Platform; - public IMSBuildPropertySet Group; + public MSBuildPropertyGroup Group; public bool Exists; public bool IsNew; // The group did not exist in the original file } @@ -2150,8 +2243,6 @@ namespace MonoDevelop.Projects disableFastUpToDateCheck = msproject.EvaluatedProperties.GetValue ("DisableFastUpToDateCheck", false); msproject.EvaluatedProperties.ReadObjectProperties (this, GetType (), true); - - RemoveDuplicateItems (msproject); } protected virtual void OnReadProject (ProgressMonitor monitor, MSBuildProject msproject) @@ -2166,6 +2257,15 @@ namespace MonoDevelop.Projects foreach (var cgrp in configData) LoadConfiguration (monitor, cgrp, cgrp.Config, cgrp.Platform); + timer.Trace ("Read run configurations"); + + List<ConfigData> runConfigData = new List<ConfigData> (); + GetRunConfigData (runConfigData, msproject, true); + GetRunConfigData (runConfigData, userProject, true); + + foreach (var cgrp in runConfigData) + LoadRunConfiguration (monitor, cgrp, cgrp.Config); + // Read extended properties timer.Trace ("Read extended properties"); @@ -2319,50 +2419,110 @@ namespace MonoDevelop.Projects config.Read (grp); } - void RemoveDuplicateItems (MSBuildProject msproject) + void GetRunConfigData (List<ConfigData> configData, MSBuildProject msproject, bool includeEvaluated) { -/* timer.Trace ("Checking for duplicate items"); - - var uniqueIncludes = new Dictionary<string,object> (); - var toRemove = new List<MSBuildItem> (); - foreach (MSBuildItem bi in msproject.GetAllItems ()) { - object existing; - string key = bi.Name + "<" + bi.Include; - if (!uniqueIncludes.TryGetValue (key, out existing)) { - uniqueIncludes[key] = bi; - continue; - } - var exBi = existing as MSBuildItem; - if (exBi != null) { - if (exBi.Condition != bi.Condition || exBi.Element.InnerXml != bi.Element.InnerXml) { - uniqueIncludes[key] = new List<MSBuildItem> { exBi, bi }; - } else { - toRemove.Add (bi); - } - continue; + if (msproject == null) + return; + + foreach (MSBuildPropertyGroup cgrp in msproject.PropertyGroups) { + string configName; + if (ParseRunConfigurationCondition (cgrp.Condition, out configName)) { + // If a group for this configuration already was found, set the new group. If there are changes we want to modify the last group. + var existing = configData.FirstOrDefault (cd => cd.Config == configName); + if (existing == null) + configData.Add (new ConfigData (configName, null, cgrp)); + else + existing.Group = cgrp; } + } + if (includeEvaluated) { + var configValues = msproject.ConditionedProperties.GetAllPropertyValues ("RunConfiguration"); - var exList = (List<MSBuildItem>)existing; - bool found = false; - foreach (var m in (exList)) { - if (m.Condition == bi.Condition && m.Element.InnerXml == bi.Element.InnerXml) { - found = true; - break; - } - } - if (!found) { - exList.Add (bi); - } else { - toRemove.Add (bi); + foreach (var c in configValues) { + if (!configData.Any (cd => cd.Config == c)) + configData.Add (new ConfigData (c, "", null)); } } - if (toRemove.Count == 0) - return; + } + + bool ParseRunConfigurationCondition (string cond, out string configName) + { + configName = null; + int i = cond.IndexOf ("==", StringComparison.Ordinal); + if (i == -1) + return false; + if (cond.Substring (0, i).Trim () == "'$(RunConfiguration)'") + return ExtractConfigName (cond.Substring (i + 2), out configName); + return false; + } + + void LoadRunConfiguration (ProgressMonitor monitor, ConfigData cgrp, string configName) + { + var runConfig = (ProjectRunConfiguration)CreateUninitializedRunConfiguration (configName); + if (cgrp.Group != null) { + runConfig.MainPropertyGroup = cgrp.Group; + runConfig.StoreInUserFile = cgrp.Group.ParentProject == userProject; + } + runConfig.MainPropertyGroup.ResetIsNewFlags (); + InitRunConfiguration (runConfig); + projectExtension.OnReadRunConfiguration (monitor, runConfig, runConfig.Properties); + runConfigurations.Add (runConfig); + } + + void InitRunConfiguration (ProjectRunConfiguration config) + { + var pi = CreateProjectInstaceForRunConfiguration (config.Name); + config.Properties = pi.GetPropertiesLinkedToGroup (config.MainPropertyGroup); + config.ProjectInstance = pi; + } + + MSBuildProjectInstance CreateProjectInstaceForRunConfiguration (string name, bool onlyEvaluateProperties = true) + { + var pi = PrepareProjectInstaceForRunConfiguration (name, onlyEvaluateProperties); + pi.Evaluate (); + return pi; + } + + async Task<MSBuildProjectInstance> CreateProjectInstaceForRunConfigurationAsync (string name, bool onlyEvaluateProperties = true) + { + var pi = PrepareProjectInstaceForRunConfiguration (name, onlyEvaluateProperties); + await pi.EvaluateAsync (); + return pi; + } + + MSBuildProjectInstance PrepareProjectInstaceForRunConfiguration (string name, bool onlyEvaluateProperties) + { + var pi = sourceProject.CreateInstance (); + pi.SetGlobalProperty ("BuildingInsideVisualStudio", "true"); + pi.SetGlobalProperty ("RunConfiguration", name); + pi.OnlyEvaluateProperties = onlyEvaluateProperties; + return pi; + } + + protected virtual ProjectRunConfiguration OnCreateRunConfiguration (string name) + { + return new ProjectRunConfiguration (name); + } + + protected virtual void OnReadRunConfiguration (ProgressMonitor monitor, ProjectRunConfiguration runConfig, IPropertySet grp) + { + runConfig.Read (grp); + } + + internal void OnRunConfigurationsAdded (IEnumerable<SolutionItemRunConfiguration> items) + { + // Initialize the property group only if the project is not being loaded (in which case it will + // be initialized by the ReadProject method) or if the project is new (because it will be initialized + // after the project is fully written, since only then all imports are in place + if (!Loading && !sourceProject.IsNewProject) { + foreach (var s in items) + InitRunConfiguration ((ProjectRunConfiguration)s); + } + } - timer.Trace ("Removing duplicate items"); + internal void OnRunConfigurationRemoved (IEnumerable<SolutionItemRunConfiguration> items) + { - foreach (var t in toRemove) - msproject.RemoveItem (t);*/ } internal void LoadProjectItems (MSBuildProject msproject, ProjectItemFlags flags, HashSet<MSBuildItem> loadedItems) @@ -2458,6 +2618,20 @@ namespace MonoDevelop.Projects } } +/* if (runConfigurations.Count > 0) { + // Set the default configuration of the project. + // First of the properties that defines the default run configuration + var defaultConfProp = globalGroup.GetProperties ().FirstOrDefault (p => p.Name == "RunConfiguration" && IsDefaultSetter (p)); + + if (msproject.IsNewProject || (defaultConfProp != null)) { + // If there is no run configuration property, or if the configuration doesn't exist anymore, give it a new value + if (defaultConfProp == null || !runConfigurations.Any (c => c.Name == defaultConfProp.UnevaluatedValue)) { + var runConfig = runConfigurations.FirstOrDefault (c => c.Name == "Default") ?? runConfigurations [0]; + globalGroup.SetValue ("RunConfiguration", runConfig.Name, condition: " '$(RunConfiguration)' == '' "); + } + } + }*/ + if (TypeGuid == MSBuildProjectService.GenericItemGuid) { DataType dt = MSBuildProjectService.DataContext.GetConfigurationDataType (GetType ()); globalGroup.SetValue ("ItemType", dt.Name); @@ -2496,10 +2670,35 @@ namespace MonoDevelop.Projects { IMSBuildPropertySet globalGroup = msproject.GetGlobalPropertyGroup (); - // Configurations + WriteConfigurations (monitor, msproject, globalGroup); + + WriteRunConfigurations (monitor, msproject, globalGroup); + + SaveProjectItems (monitor, msproject, usedMSBuildItems); + + if (msproject.IsNewProject) { + foreach (var im in DefaultImports) + msproject.AddNewImport (im); + } + + foreach (var im in importsAdded) { + if (msproject.GetImport (im.Name, im.Condition) == null) + msproject.AddNewImport (im.Name, im.Condition); + } + foreach (var im in importsRemoved) { + var i = msproject.GetImport (im.Name, im.Condition); + if (i != null) + msproject.RemoveImport (i); + } + importsAdded.Clear (); + importsRemoved.Clear (); + msproject.WriteExternalProjectProperties (this, GetType (), true); + } + void WriteConfigurations (ProgressMonitor monitor, MSBuildProject msproject, IMSBuildPropertySet globalGroup) + {
if (Configurations.Count > 0) { - + List<ConfigData> configData = GetConfigData (msproject, false); // Write configuration data, creating new property groups if necessary @@ -2515,7 +2714,7 @@ namespace MonoDevelop.Projects int i = Configurations.IndexOf (conf); if (i != -1 && i + 1 < Configurations.Count) nextConf = ((ProjectConfiguration)Configurations [i + 1]).MainPropertyGroup; - + msproject.AddPropertyGroup (pg, true, nextConf); pg.Condition = BuildConfigCondition (conf.Name, conf.Platform); cdata = new ConfigData (conf.Name, conf.Platform, pg); @@ -2579,26 +2778,85 @@ namespace MonoDevelop.Projects foreach (ProjectConfiguration config in Configurations) config.MainPropertyGroup.ResetIsNewFlags (); } + } - SaveProjectItems (monitor, msproject, usedMSBuildItems); + void WriteRunConfigurations (ProgressMonitor monitor, MSBuildProject msproject, IMSBuildPropertySet globalGroup) + {
+ List<ConfigData> configData = new List<ConfigData> (); + GetRunConfigData (configData, msproject, false); + GetRunConfigData (configData, userProject, false); - if (msproject.IsNewProject) { - foreach (var im in DefaultImports) - msproject.AddNewImport (im); - } + if (RunConfigurations.Count > 0) { - foreach (var im in importsAdded) { - if (msproject.GetImport (im.Name, im.Condition) == null) - msproject.AddNewImport (im.Name, im.Condition); + // Write configuration data, creating new property groups if necessary + + var defaultConfig = CreateRunConfigurationInternal ("Default"); + + foreach (ProjectRunConfiguration runConfig in RunConfigurations) { + + MSBuildPropertyGroup pg = runConfig.MainPropertyGroup; + ConfigData cdata = configData.FirstOrDefault (cd => cd.Group == pg); + var targetProject = runConfig.StoreInUserFile ? userProject : msproject; + + if (runConfig.IsDefaultConfiguration && runConfig.Equals (defaultConfig)) { + // If the default configuration has the default values, then there is no need to save it. + // If this configuration was added after loading the project, we are not adding it to the msproject and we are done. + // If this configuration was loaded from the project and later modified to the default values, we dont set cdata.Exists=true, + // so it will be removed from the msproject below. + continue; + } + + // Create the user project file if it doesn't yet exist + if (targetProject == null) + targetProject = userProject = CreateUserProject (msproject); + + if (cdata == null) { + // Try to keep the groups in the same order as the config list + MSBuildObject nextConfig = null; + int i = runConfigurations.IndexOf (runConfig); + if (i != -1 && i + 1 < runConfigurations.Count) + nextConfig = runConfigurations.Skip (i).Cast<ProjectRunConfiguration> ().FirstOrDefault (s => s.MainPropertyGroup.ParentProject == targetProject)?.MainPropertyGroup; + targetProject.AddPropertyGroup (pg, true, nextConfig); + pg.Condition = BuildRunConfigurationCondition (runConfig.Name); + cdata = new ConfigData (runConfig.Name, null, pg); + cdata.IsNew = true; + configData.Add (cdata); + } else { + // The configuration name may have changed + if (cdata.Config != runConfig.Name) { + ((MSBuildPropertyGroup)cdata.Group).Condition = BuildRunConfigurationCondition (runConfig.Name); + cdata.Config = runConfig.Name; + } + var groupInUserProject = cdata.Group.ParentProject == userProject; + if (groupInUserProject != runConfig.StoreInUserFile) { + cdata.Group.ParentProject.Remove (cdata.Group); + targetProject.AddPropertyGroup (cdata.Group); + } + } + + cdata.Exists = true; + ProjectExtension.OnWriteRunConfiguration (monitor, runConfig, runConfig.Properties); + runConfig.MainPropertyGroup.PurgeDefaultProperties (); + } } - foreach (var im in importsRemoved) { - var i = msproject.GetImport (im.Name, im.Condition); - if (i != null) - msproject.RemoveImport (i); + + // Remove groups corresponding to configurations that have been removed + foreach (ConfigData cd in configData) { + if (!cd.Exists) + cd.Group.ParentProject.Remove (cd.Group); } - importsAdded.Clear (); - importsRemoved.Clear (); - msproject.WriteExternalProjectProperties (this, GetType (), true); + + foreach (ProjectRunConfiguration runConfig in runConfigurations) + runConfig.MainPropertyGroup.ResetIsNewFlags (); + } + + MSBuildProject CreateUserProject (MSBuildProject msproject) + { + var p = new MSBuildProject (msproject.EngineManager); + // Remove the main property group + p.Remove (p.PropertyGroups.First ()); + p.FileName = msproject.FileName + ".user"; + return p; } protected virtual void OnWriteConfiguration (ProgressMonitor monitor, ProjectConfiguration config, IPropertySet pset) @@ -2606,6 +2864,11 @@ namespace MonoDevelop.Projects config.Write (pset); } + protected virtual void OnWriteRunConfiguration (ProgressMonitor monitor, ProjectRunConfiguration config, IPropertySet pset) + { + config.Write (pset); + } + IEnumerable<MergedProperty> GetMergeToProjectProperties (List<ConfigData> configData) { Dictionary<string,MergedProperty> mergeProps = new Dictionary<string, MergedProperty> (); @@ -2781,6 +3044,15 @@ namespace MonoDevelop.Projects return null; } + ConfigData FindPropertyGroup (List<ConfigData> configData, ProjectRunConfiguration config) + { + foreach (ConfigData data in configData) { + if (data.Config == config.Name) + return data; + } + return null; + } + string BuildConfigCondition (string config, string platform) { if (platform.Length == 0) @@ -2788,6 +3060,11 @@ namespace MonoDevelop.Projects return " '$(Configuration)|$(Platform)' == '" + config + "|" + platform + "' "; } + string BuildRunConfigurationCondition (string name) + { + return " '$(RunConfiguration)' == '" + name + "' "; + } + bool IsMergeToProjectProperty (ItemProperty prop) { foreach (object at in prop.CustomAttributes) { @@ -2950,6 +3227,21 @@ namespace MonoDevelop.Projects Project.OnGetTypeTags (types); } + internal protected override ProjectRunConfiguration OnCreateRunConfiguration (string name) + { + return Project.OnCreateRunConfiguration (name); + } + + internal protected override void OnReadRunConfiguration (ProgressMonitor monitor, ProjectRunConfiguration runConfig, IPropertySet properties) + { + Project.OnReadRunConfiguration (monitor, runConfig, properties); + } + + internal protected override void OnWriteRunConfiguration (ProgressMonitor monitor, ProjectRunConfiguration runConfig, IPropertySet properties) + { + Project.OnWriteRunConfiguration (monitor, runConfig, properties); + } + internal protected override Task<TargetEvaluationResult> OnRunTarget (ProgressMonitor monitor, string target, ConfigurationSelector configuration, TargetEvaluationContext context) { return Project.DoRunTarget (monitor, target, configuration, context); diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectCreateInformation.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectCreateInformation.cs index 316dda8010..db86bf242e 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectCreateInformation.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectCreateInformation.cs @@ -25,6 +25,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +using System; using MonoDevelop.Core; using MonoDevelop.Core.StringParsing; @@ -82,5 +83,10 @@ namespace MonoDevelop.Projects ActiveConfiguration = projectCreateInformation.ActiveConfiguration; Parameters = projectCreateInformation.Parameters; } + + /// <summary> + /// A callback that will be invoked to initialize the project + /// </summary> + public Action<SolutionItem> TemplateInitializationCallback { get; set; } } } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectExtension.cs index 957f06616c..a4a234ccd5 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectExtension.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectExtension.cs @@ -60,6 +60,21 @@ namespace MonoDevelop.Projects return next.SupportsFlavor (guid); } + internal protected virtual ProjectRunConfiguration OnCreateRunConfiguration (string name) + { + return next.OnCreateRunConfiguration (name); + } + + internal protected virtual void OnReadRunConfiguration (ProgressMonitor monitor, ProjectRunConfiguration config, IPropertySet properties) + { + next.OnReadRunConfiguration (monitor, config, properties); + } + + internal protected virtual void OnWriteRunConfiguration (ProgressMonitor monitor, ProjectRunConfiguration config, IPropertySet properties) + { + next.OnWriteRunConfiguration (monitor, config, properties); + } + internal protected virtual Task<TargetEvaluationResult> OnRunTarget (ProgressMonitor monitor, string target, ConfigurationSelector configuration, TargetEvaluationContext context) { return next.OnRunTarget (monitor, target, configuration, context); diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectFeature.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectFeature.cs index 75ac1a1b7e..fd9becc607 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectFeature.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectFeature.cs @@ -33,7 +33,8 @@ namespace MonoDevelop.Projects None = 0, Build = 1, Execute = 2, - Configurations = 4 + Configurations = 4, + RunConfigurations = 8 } } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectRunConfiguration.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectRunConfiguration.cs new file mode 100644 index 0000000000..efaa559a58 --- /dev/null +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectRunConfiguration.cs @@ -0,0 +1,156 @@ +// +// ProjectRunConfiguration.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 MonoDevelop.Projects.MSBuild; +using System.Linq; +using System.Collections.Generic; + +namespace MonoDevelop.Projects +{ + public class ProjectRunConfiguration: SolutionItemRunConfiguration + { + IPropertySet properties; + MSBuildPropertyGroup mainPropertyGroup; + + public ProjectRunConfiguration (string name): base (name) + { + } + + internal protected virtual void Initialize (Project project) + { + // There may be run configuration properties defined in the + // main property group in the project. Those values have to + // be initially loaded in new run configurations. + + using (var pi = project.MSBuildProject.CreateInstance ()) { + pi.SetGlobalProperty ("BuildingInsideVisualStudio", "true"); + pi.SetGlobalProperty ("RunConfiguration", ""); + pi.OnlyEvaluateProperties = true; + pi.Evaluate (); + var lg = pi.GetPropertiesLinkedToGroup (MainPropertyGroup); + Read (lg); + properties = MainPropertyGroup; + MainPropertyGroup.UnlinkFromProjectInstance (); + } + } + + public new Project ParentItem { + get { return (Project)base.ParentItem; } + } + + /// <summary> + /// Copies the data of a run configuration into this configuration + /// </summary> + /// <param name="config">Configuration from which to get the data.</param> + /// <param name="isRename">If true, it means that the copy is being made as a result of a rename or clone operation. In this case, + /// the overriden method may change the value of some properties that depend on the configuration name.</param> + public void CopyFrom (ProjectRunConfiguration config, bool isRename = false) + { + StoreInUserFile = config.StoreInUserFile; + OnCopyFrom (config, isRename); + } + + protected virtual void OnCopyFrom (ProjectRunConfiguration config, bool isRename) + { + } + + internal protected virtual void Read (IPropertySet pset) + { + properties = pset; + pset.ReadObjectProperties (this, GetType (), true); + } + + internal protected virtual void Write (IPropertySet pset) + { + pset.WriteObjectProperties (this, GetType (), true); + } + + internal bool Equals (ProjectRunConfiguration other) + { + var dict1 = new Dictionary<string, string> (); + var dict2 = new Dictionary<string, string> (); + + var thisData = new ProjectItemMetadata (); + Write (thisData); + GetProps (MainPropertyGroup, dict1); + GetProps (thisData, dict1); + + var otherData = new ProjectItemMetadata (); + other.Write (otherData); + GetProps (other.MainPropertyGroup, dict2); + GetProps (otherData, dict2); + + if (dict1.Count != dict2.Count) + return false; + foreach (var tp in dict1) { + string v; + if (!dict2.TryGetValue (tp.Key, out v) || tp.Value != v) + return false; + } + return true; + } + + void GetProps (IPropertySet p, Dictionary<string,string> dict) + { + foreach (var prop in p.GetProperties ()) + dict [prop.Name] = prop.Value; + } + + /// <summary> + /// Property set where the properties for this configuration are defined. + /// </summary> + public IPropertySet Properties { + get { + return properties ?? MainPropertyGroup; + } + internal set { + properties = value; + } + } + + internal MSBuildPropertyGroup MainPropertyGroup { + get { + if (mainPropertyGroup == null) { + if (ParentItem == null) + mainPropertyGroup = new MSBuildPropertyGroup (); + else + mainPropertyGroup = ParentItem.MSBuildProject.CreatePropertyGroup (); + mainPropertyGroup.IgnoreDefaultValues = true; + } + return mainPropertyGroup; + } + set { + mainPropertyGroup = value; + mainPropertyGroup.IgnoreDefaultValues = true; + } + } + + internal MSBuildProjectInstance ProjectInstance { get; set; } + + public bool StoreInUserFile { get; set; } = true; + } +} + diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RunConfiguration.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RunConfiguration.cs new file mode 100644 index 0000000000..5235be4985 --- /dev/null +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RunConfiguration.cs @@ -0,0 +1,59 @@ +// +// RunConfiguration.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; + +namespace MonoDevelop.Projects +{ + public abstract class RunConfiguration + { + /// <summary> + /// Display name of the configuration + /// </summary> + public abstract string Name { get; } + + /// <summary> + /// Unique id of the configuration + /// </summary> + public abstract string Id { get; } + + /// <summary> + /// Icon + /// </summary> + public virtual string IconId { + get { return null; } + } + + /// <summary> + /// One line description of the configuration + /// </summary> + /// <value>The summary.</value> + public virtual string Summary { + get { return string.Empty; } + } + } +} + diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RunConfigurationCollection.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RunConfigurationCollection.cs new file mode 100644 index 0000000000..91bf3e9704 --- /dev/null +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/RunConfigurationCollection.cs @@ -0,0 +1,65 @@ +// +// RunConfigurationCollection.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; + +namespace MonoDevelop.Projects +{ + public class RunConfigurationCollection: ItemCollection<ProjectRunConfiguration> + { + SolutionItem parentItem; + + public RunConfigurationCollection () + { + } + + internal RunConfigurationCollection (SolutionItem parentItem) + { + this.parentItem = parentItem; + } + + protected override void OnItemsAdded (IEnumerable<ProjectRunConfiguration> items) + { + if (parentItem != null) { + foreach (var conf in items) + ((SolutionItemRunConfiguration)conf).ParentItem = parentItem; + } + base.OnItemsAdded (items); + (parentItem as Project)?.OnRunConfigurationsAdded (items); + } + + protected override void OnItemsRemoved (IEnumerable<ProjectRunConfiguration> items) + { + if (parentItem != null) { + foreach (var conf in items) + ((SolutionItemRunConfiguration)conf).ParentItem = null; + } + base.OnItemsRemoved (items); + (parentItem as Project)?.OnRunConfigurationRemoved (items); + } + } +} + diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SingleItemSolutionRunConfiguration.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SingleItemSolutionRunConfiguration.cs new file mode 100644 index 0000000000..3a26f1c680 --- /dev/null +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SingleItemSolutionRunConfiguration.cs @@ -0,0 +1,45 @@ +// +// SingleItemSolutionRunConfiguration.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; +namespace MonoDevelop.Projects +{ + public sealed class SingleItemSolutionRunConfiguration: SolutionRunConfiguration + { + public SingleItemSolutionRunConfiguration (SolutionItem item, SolutionItemRunConfiguration config): base (item.ItemId + "|" + config?.Name) + { + Item = item; + RunConfiguration = config; + if (config != null && !config.IsDefaultConfiguration) + SetName (item.Name + " – " + config.Name); + else + SetName (item.Name); + } + + public SolutionItem Item { get; private set; } + public SolutionItemRunConfiguration RunConfiguration { get; private set; } + } +} + diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Solution.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Solution.cs index 05a406c308..8c49995ef0 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Solution.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Solution.cs @@ -43,24 +43,22 @@ using MonoDevelop.Projects.MSBuild; namespace MonoDevelop.Projects { [ProjectModelDataItem] - public class Solution: WorkspaceItem, IConfigurationTarget, IPolicyProvider, IBuildTarget, IMSBuildFileObject + public class Solution: WorkspaceItem, IConfigurationTarget, IPolicyProvider, IBuildTarget, IMSBuildFileObject, IRunTarget { internal object MemoryProbe = Counters.SolutionsInMemory.CreateMemoryProbe (); + SolutionFolder rootFolder; string defaultConfiguration; MSBuildFileFormat format; bool loadingFromConstructor; - SolutionItem startupItem; - List<SolutionItem> startupItems; - bool singleStartup = true; + SolutionRunConfiguration startupSolutionConfiguration; - // Used for serialization only - List<string> multiStartupItems; - string startItemFileName; - ReadOnlyCollection<SolutionItem> solutionItems; SolutionConfigurationCollection configurations; + SolutionRunConfigurationCollection runConfigurations; + MultiItemSolutionRunConfiguration multiStartupConfig = new MultiItemSolutionRunConfiguration (MultiStartupConfigId, "Multi-Startup"); + const string MultiStartupConfigId = "MonoDevelop.Projects.MultiStartup"; MSBuildEngineManager msbuildEngineManager = new MSBuildEngineManager (); @@ -82,6 +80,7 @@ namespace MonoDevelop.Projects loadingFromConstructor = loading; Counters.SolutionsLoaded++; configurations = new SolutionConfigurationCollection (this); + runConfigurations = new SolutionRunConfigurationCollection (this); format = MSBuildFileFormat.DefaultFormat; Initialize (this); } @@ -162,99 +161,56 @@ namespace MonoDevelop.Projects return solutionItems; } } - - public SolutionItem StartupItem { + + public SolutionRunConfiguration StartupConfiguration { get { - if (startItemFileName != null) { - startupItem = FindSolutionItem (startItemFileName); - startItemFileName = null; - singleStartup = true; - } - if (startupItem == null && singleStartup) { - var its = GetAllItems<SolutionItem> (); - if (its.Any ()) - startupItem = its.FirstOrDefault (it => it.SupportsExecute ()); + return startupSolutionConfiguration; + } + set { + if (startupSolutionConfiguration != value) { + var oldIt = StartupItem; + startupSolutionConfiguration = value; + NotifyModified (); + OnStartupConfigurationChanged (null); + if (oldIt != StartupItem) + OnStartupItemChanged (null); } - return startupItem; + } + } + + public SolutionItem StartupItem { + get { + return (StartupConfiguration as SingleItemSolutionRunConfiguration)?.Item; } set { - startupItem = value; - startItemFileName = null; - NotifyModified (); - OnStartupItemChanged(null); + if (value != StartupItem) + StartupConfiguration = GetRunConfigurations ().OfType<SingleItemSolutionRunConfiguration> ().FirstOrDefault (co => co.Item == value); } } - + public bool SingleStartup { get { - if (startItemFileName != null) - return true; - if (multiStartupItems != null) - return false; - return singleStartup; + return StartupConfiguration is SingleItemSolutionRunConfiguration; } set { - if (SingleStartup == value) + if (value == SingleStartup) return; - singleStartup = value; if (value) { - if (MultiStartupItems.Count > 0) - startupItem = startupItems [0]; + StartupItem = multiStartupConfig.Items.FirstOrDefault () ?? GetRunConfigurations ().OfType<SingleItemSolutionRunConfiguration> ().Select (i => i.Item).FirstOrDefault (); } else { - MultiStartupItems.Clear (); - if (StartupItem != null) - MultiStartupItems.Add (StartupItem); + if (!runConfigurations.Contains (multiStartupConfig)) + runConfigurations.Add (multiStartupConfig); + StartupConfiguration = multiStartupConfig; } - NotifyModified (); - OnStartupItemChanged(null); } } public List<SolutionItem> MultiStartupItems { get { - if (multiStartupItems != null) { - startupItems = new List<SolutionItem> (); - foreach (string file in multiStartupItems) { - SolutionItem it = FindSolutionItem (file); - if (it != null) - startupItems.Add (it); - } - multiStartupItems = null; - singleStartup = false; - } - else if (startupItems == null) - startupItems = new List<SolutionItem> (); - return startupItems; + return multiStartupConfig.Items; } } - // Used by serialization only - internal string StartupItemFileName { - get { - if (SingleStartup && StartupItem != null) - return StartupItem.FileName; - else - return null ; - } - set { startItemFileName = value; } - } - - internal List<string> MultiStartupItemFileNames { - get { - if (SingleStartup) - return null; - if (multiStartupItems != null) - return multiStartupItems; - List<string> files = new List<string> (); - foreach (SolutionItem item in MultiStartupItems) - files.Add (item.FileName); - return files; - } - set { - multiStartupItems = value; - } - } - /// <summary> /// Gets the author information for this solution. If no specific information is set for this solution, it /// will return the author defined in the global settings. @@ -285,6 +241,44 @@ namespace MonoDevelop.Projects { await base.OnEndLoad (); LoadItemProperties (UserProperties, RootFolder, "MonoDevelop.Ide.ItemProperties"); + + bool startupConfigSet = false; + + var sitem = UserProperties.GetValue<string> ("StartupItem"); + if (!string.IsNullOrEmpty (sitem)) { + // Old StartupItem property. Find the corresponding SingleItemSolutionRunConfiguration instance and get rid of the property. + var startItemFileName = GetAbsoluteChildPath (sitem); + var item = FindSolutionItem (startItemFileName); + if (item != null) { + StartupConfiguration = GetRunConfigurations ().OfType<SingleItemSolutionRunConfiguration> ().FirstOrDefault (c => c.Item == item); + startupConfigSet = true; + } + UserProperties.RemoveValue ("StartupItem"); + } + + var sitems = UserProperties.GetValue<string []> ("StartupItems"); + if (sitems != null && sitems.Length > 0) { + // Old StartupItems property. Create a corresponding MultiItemSolutionRunConfiguration. + var multiStartupItems = sitems.Select (p => (string)GetAbsoluteChildPath (p)).Select (file => FindSolutionItem (file)).Where (i => i != null); + multiStartupConfig.Items.Clear (); + multiStartupConfig.Items.AddRange (multiStartupItems.ToArray ()); + runConfigurations.Add (multiStartupConfig); + if (!startupConfigSet) { + // If the config has not been set by StartupItem it means that this is an old solution that had been configured with multiple startup. + // Select the multi-startup config in this case. + StartupConfiguration = multiStartupConfig; + startupConfigSet = true; + } + } + + if (!startupConfigSet) { + // Startup configuration has not been set by legacy properties. Do it now. + var sconfig = UserProperties.GetValue<string> ("StartupConfiguration"); + if (!string.IsNullOrEmpty (sconfig)) + StartupConfiguration = GetRunConfigurations ().FirstOrDefault (c => c.Id == sconfig); + else + StartupConfiguration = GetRunConfigurations ().FirstOrDefault (); + } } internal protected override Task OnSave (ProgressMonitor monitor) @@ -292,24 +286,15 @@ namespace MonoDevelop.Projects return FileFormat.WriteFile (FileName, this, monitor); } - protected override async Task OnLoadUserProperties () - { - await base.OnLoadUserProperties (); - var sitem = UserProperties.GetValue<string> ("StartupItem"); - if (!string.IsNullOrEmpty (sitem)) - startItemFileName = GetAbsoluteChildPath (sitem); - - var sitems = UserProperties.GetValue<string[]> ("StartupItems"); - if (sitems != null && sitems.Length > 0) - multiStartupItems = sitems.Select (p => (string) GetAbsoluteChildPath (p)).ToList (); - } - protected override async Task OnSaveUserProperties () { - UserProperties.SetValue ("StartupItem", (string) GetRelativeChildPath (StartupItemFileName)); - if (MultiStartupItemFileNames != null) { - UserProperties.SetValue ("StartupItems", MultiStartupItemFileNames.Select (p => (string)GetRelativeChildPath (p)).ToArray ()); - } else + UserProperties.SetValue ("StartupConfiguration", (string)StartupConfiguration?.Id); + + // Save the multi-startup configuration only if it is the one that's selected + var msc = StartupConfiguration as MultiItemSolutionRunConfiguration; + if (msc != null) + UserProperties.SetValue ("StartupItems", msc.Items.Select (p => (string)GetRelativeChildPath (p.FileName)).ToArray ()); + else UserProperties.RemoveValue ("StartupItems"); CollectItemProperties (UserProperties, RootFolder, "MonoDevelop.Ide.ItemProperties"); @@ -402,7 +387,7 @@ namespace MonoDevelop.Projects { return (SolutionConfiguration) configuration.GetConfiguration (this) ?? DefaultConfiguration; } - + public SolutionFolderItem GetSolutionItem (string itemId) { foreach (SolutionFolderItem item in Items) @@ -638,6 +623,21 @@ namespace MonoDevelop.Projects return true; } + internal void OnRunConfigurationsAdded (IEnumerable<SolutionRunConfiguration> items) + { + NotifyRunConfigurationsChanged (); + } + + internal void OnRunConfigurationRemoved (IEnumerable<SolutionRunConfiguration> items) + { + NotifyRunConfigurationsChanged (); + } + + internal void NotifyRunConfigurationsChanged () + { + RunConfigurationsChanged?.Invoke (this, EventArgs.Empty); + } + public Task<BuildResult> Clean (ProgressMonitor monitor, string configuration) { return Clean (monitor, (SolutionConfigurationSelector) configuration); @@ -670,40 +670,134 @@ namespace MonoDevelop.Projects public Task Execute (ProgressMonitor monitor, ExecutionContext context, string configuration) { - return Execute (monitor, context, (SolutionConfigurationSelector) configuration); + return Execute (monitor, context, (SolutionConfigurationSelector) configuration, StartupConfiguration); } public Task Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) { - return SolutionExtension.Execute (monitor, context, configuration); + return Execute (monitor, context, configuration, StartupConfiguration); + } + + public Task Execute (ProgressMonitor monitor, ExecutionContext context, string configuration, SolutionRunConfiguration runConfiguration) + { + return Execute (monitor, context, (SolutionConfigurationSelector)configuration, runConfiguration); + } + + public Task Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionRunConfiguration runConfiguration) + { + return SolutionExtension.Execute (monitor, context, configuration, runConfiguration ?? StartupConfiguration); + } + + Task IRunTarget.Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, RunConfiguration runConfiguration) + { + if (runConfiguration != null && !(runConfiguration is SolutionRunConfiguration)) + throw new ArgumentException ("Invalid configuration type"); + return Execute (monitor, context, configuration, (SolutionRunConfiguration)runConfiguration); } public Task PrepareExecution (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) { - return SolutionExtension.PrepareExecution (monitor, context, configuration); + return PrepareExecution (monitor, context, configuration, StartupConfiguration); + } + + public Task PrepareExecution (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionRunConfiguration runConfiguration) + { + return SolutionExtension.PrepareExecution (monitor, context, configuration, runConfiguration); + } + + Task IRunTarget.PrepareExecution (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, RunConfiguration runConfiguration) + { + if (runConfiguration != null && !(runConfiguration is SolutionRunConfiguration)) + throw new ArgumentException ("Invalid configuration type"); + return PrepareExecution (monitor, context, configuration, (SolutionRunConfiguration)runConfiguration); } public bool CanExecute (ExecutionContext context, string configuration) { - return CanExecute (context, (SolutionConfigurationSelector) configuration); + return CanExecute (context, (SolutionConfigurationSelector) configuration, StartupConfiguration); } public bool CanExecute (ExecutionContext context, ConfigurationSelector configuration) { - return SolutionExtension.CanExecute (context, configuration); + return CanExecute (context, configuration, StartupConfiguration); + } + + public bool CanExecute (ExecutionContext context, string configuration, SolutionRunConfiguration runConfiguration) + { + return CanExecute (context, (SolutionConfigurationSelector)configuration, runConfiguration); + } + + public bool CanExecute (ExecutionContext context, ConfigurationSelector configuration, SolutionRunConfiguration runConfiguration) + { + return SolutionExtension.CanExecute (context, configuration, runConfiguration); + } + + bool IRunTarget.CanExecute (ExecutionContext context, ConfigurationSelector configuration, RunConfiguration runConfiguration) + { + if (runConfiguration != null && !(runConfiguration is SolutionRunConfiguration)) + throw new ArgumentException ("Invalid configuration type"); + return CanExecute (context, configuration, (SolutionRunConfiguration)runConfiguration); + } + + public IEnumerable<SolutionRunConfiguration> GetRunConfigurations () + { + return SolutionExtension.OnGetRunConfigurations (); + } + + IEnumerable<RunConfiguration> IRunTarget.GetRunConfigurations () + { + return GetRunConfigurations (); + } + + protected virtual IEnumerable<SolutionRunConfiguration> OnGetRunConfigurations () + { + IEnumerable<SolutionRunConfiguration> res = runConfigurations; + foreach (var it in GetAllSolutionItems ().Where (i => i.SupportsExecute ())) { + var configs = it.GetRunConfigurations ().ToArray (); + if (!configs.Any ()) + res = res.Concat (new SingleItemSolutionRunConfiguration (it, null)); + else if (configs.Length == 1) + res = res.Concat (new SingleItemSolutionRunConfiguration (it, configs[0])); + else + res = res.Concat (it.GetRunConfigurations ().Select (c => new SingleItemSolutionRunConfiguration (it, c))); + } + return res; } public IEnumerable<ExecutionTarget> GetExecutionTargets (string configuration) { - return GetExecutionTargets ((SolutionConfigurationSelector) configuration); + return GetExecutionTargets ((SolutionConfigurationSelector) configuration, StartupConfiguration); } public IEnumerable<ExecutionTarget> GetExecutionTargets (ConfigurationSelector configuration) { + return GetExecutionTargets (configuration, StartupConfiguration); + } + + public IEnumerable<ExecutionTarget> GetExecutionTargets (string configuration, SolutionRunConfiguration runConfiguration) + { + return GetExecutionTargets ((SolutionConfigurationSelector)configuration, runConfiguration); + } + + public IEnumerable<ExecutionTarget> GetExecutionTargets (ConfigurationSelector configuration, SolutionRunConfiguration runConfiguration) + { + return SolutionExtension.GetExecutionTargets (this, configuration, runConfiguration); + } + + IEnumerable<ExecutionTarget> IRunTarget.GetExecutionTargets (ConfigurationSelector configuration, RunConfiguration runConfiguration) + { + if (runConfiguration != null && !(runConfiguration is SolutionRunConfiguration)) + throw new ArgumentException ("Invalid configuration type"); + return SolutionExtension.GetExecutionTargets (this, configuration, (SolutionRunConfiguration)runConfiguration); + } + + IEnumerable<ExecutionTarget> OnGetExecutionTargets (ConfigurationSelector configuration, SolutionRunConfiguration runConfiguration) + { return SolutionExtension.GetExecutionTargets (this, configuration); } - /*protected virtual*/ Task<BuildResult> OnBuild (ProgressMonitor monitor, ConfigurationSelector configuration, OperationContext operationContext) + /*protected virtual*/ + Task<BuildResult> OnBuild (ProgressMonitor monitor, ConfigurationSelector configuration, OperationContext operationContext) { return RootFolder.Build (monitor, configuration, operationContext:operationContext); } @@ -718,41 +812,46 @@ namespace MonoDevelop.Projects return RootFolder.Clean (monitor, configuration, operationContext); } - /*protected virtual*/ bool OnGetCanExecute(ExecutionContext context, ConfigurationSelector configuration) + /*protected virtual*/ bool OnGetCanExecute(ExecutionContext context, ConfigurationSelector configuration, SolutionRunConfiguration runConfiguration) { - if (SingleStartup) { - if (StartupItem == null) - return false; - return StartupItem.CanExecute (context, configuration); - } else { - foreach (SolutionItem it in MultiStartupItems) { + var ssc = runConfiguration as SingleItemSolutionRunConfiguration; + if (ssc != null) + return ssc.Item.CanExecute (context, configuration, ssc.RunConfiguration); + + var msc = runConfiguration as MultiItemSolutionRunConfiguration; + if (msc != null) { + foreach (SolutionItem it in msc.Items) { if (it.CanExecute (context, configuration)) return true; } return false; } + return false; } - /*protected virtual*/ async Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) + /*protected virtual*/ async Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionRunConfiguration runConfiguration) { - if (SingleStartup) { - if (StartupItem == null) { - monitor.ReportError (GettextCatalog.GetString ("Startup item not set"), null); - return; - } - await StartupItem.Execute (monitor, context, configuration); - } else { + var ssc = runConfiguration as SingleItemSolutionRunConfiguration; + if (ssc != null) { + await ssc.Item.Execute (monitor, context, configuration, ssc.RunConfiguration); + return; + } + var msc = runConfiguration as MultiItemSolutionRunConfiguration; + if (msc != null) { var tasks = new List<Task> (); var monitors = new List<AggregatedProgressMonitor> (); monitor.BeginTask ("Executing projects", 1); + + var secondaryContext = new ExecutionContext (Runtime.ProcessService.DefaultExecutionMode, context.ConsoleFactory, null); - foreach (SolutionItem it in MultiStartupItems) { + foreach (SolutionItem it in msc.Items) { if (!it.CanExecute (context, configuration)) continue; AggregatedProgressMonitor mon = new AggregatedProgressMonitor (); mon.AddFollowerMonitor (monitor, MonitorAction.ReportError | MonitorAction.ReportWarning | MonitorAction.FollowerCancel); monitors.Add (mon); tasks.Add (it.Execute (mon, context, configuration)); + context = secondaryContext; } try { await Task.WhenAll (tasks); @@ -767,7 +866,7 @@ namespace MonoDevelop.Projects } } - /*protected virtual*/ Task OnPrepareExecution (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) + /*protected virtual*/ Task OnPrepareExecution (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionRunConfiguration runConfiguration) { return Task.FromResult (0); } @@ -778,6 +877,13 @@ namespace MonoDevelop.Projects StartupItemChanged (this, e); } + void OnStartupConfigurationChanged (EventArgs e) + { + if (StartupConfigurationChanged != null) + StartupConfigurationChanged (this, e); + } + + [ThreadSafe] public MSBuildFileFormat FileFormat { get { @@ -1078,7 +1184,9 @@ namespace MonoDevelop.Projects #endregion public event EventHandler StartupItemChanged; - + public event EventHandler StartupConfigurationChanged; + public event EventHandler RunConfigurationsChanged; + public event SolutionItemChangeEventHandler SolutionItemAdded; public event SolutionItemChangeEventHandler SolutionItemRemoved; @@ -1120,19 +1228,19 @@ namespace MonoDevelop.Projects return Solution.OnClean (monitor, configuration, operationContext); } - internal protected override Task Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) + internal protected override Task Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionRunConfiguration runConfiguration) { - return Solution.OnExecute (monitor, context, configuration); + return Solution.OnExecute (monitor, context, configuration, runConfiguration); } - internal protected override Task PrepareExecution (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) + internal protected override Task PrepareExecution (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionRunConfiguration runConfiguration) { - return Solution.OnPrepareExecution (monitor, context, configuration); + return Solution.OnPrepareExecution (monitor, context, configuration, runConfiguration); } - internal protected override bool CanExecute (ExecutionContext context, ConfigurationSelector configuration) + internal protected override bool CanExecute (ExecutionContext context, ConfigurationSelector configuration, SolutionRunConfiguration runConfiguration) { - return Solution.OnGetCanExecute (context, configuration); + return Solution.OnGetCanExecute (context, configuration, runConfiguration); } internal protected override void OnReadSolution (ProgressMonitor monitor, SlnFile file) @@ -1165,6 +1273,11 @@ namespace MonoDevelop.Projects Solution.OnReadSolutionFolderItemData (monitor, properties, item); } + internal protected override IEnumerable<ExecutionTarget> GetExecutionTargets (Solution solution, ConfigurationSelector configuration, SolutionRunConfiguration runConfiguration) + { + return Solution.OnGetExecutionTargets (configuration, runConfiguration); + } + internal protected override IEnumerable<ExecutionTarget> GetExecutionTargets (Solution solution, ConfigurationSelector configuration) { yield break; @@ -1179,6 +1292,11 @@ namespace MonoDevelop.Projects { Solution.OnSetFormat (value); } + + internal protected override IEnumerable<SolutionRunConfiguration> OnGetRunConfigurations () + { + return Solution.OnGetRunConfigurations (); + } } } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionExtension.cs index 1907ade73c..a6dfcb7615 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionExtension.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionExtension.cs @@ -61,19 +61,46 @@ namespace MonoDevelop.Projects return next.Clean (monitor, configuration, operationContext); } + [Obsolete("Use the overload that takes a SolutionRunConfiguration argument")] internal protected virtual Task Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) { - return next.Execute (monitor, context, configuration); + return next.Execute (monitor, context, configuration, (SolutionRunConfiguration)context.RunConfiguration); } + [Obsolete ("Use the overload that takes a SolutionRunConfiguration argument")] internal protected virtual Task PrepareExecution (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) { - return next.PrepareExecution (monitor, context, configuration); + return next.PrepareExecution (monitor, context, configuration, (SolutionRunConfiguration)context.RunConfiguration); } + [Obsolete ("Use the overload that takes a SolutionRunConfiguration argument")] internal protected virtual bool CanExecute (ExecutionContext context, ConfigurationSelector configuration) { - return next.CanExecute (context, configuration); + return next.CanExecute (context, configuration, (SolutionRunConfiguration)context.RunConfiguration); + } + + internal protected virtual Task Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionRunConfiguration runConfiguration) + { + context.RunConfiguration = runConfiguration; +#pragma warning disable 618 // Type or member is obsolete + return Execute (monitor, context, configuration); +#pragma warning restore 618 // Type or member is obsolete + } + + internal protected virtual Task PrepareExecution (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionRunConfiguration runConfiguration) + { + context.RunConfiguration = runConfiguration; +#pragma warning disable 618 // Type or member is obsolete + return PrepareExecution (monitor, context, configuration); +#pragma warning restore 618 // Type or member is obsolete + } + + internal protected virtual bool CanExecute (ExecutionContext context, ConfigurationSelector configuration, SolutionRunConfiguration runConfiguration) + { + context.RunConfiguration = runConfiguration; +#pragma warning disable 618 // Type or member is obsolete + return CanExecute (context, configuration); +#pragma warning restore 618 // Type or member is obsolete } internal protected virtual IEnumerable<ExecutionTarget> GetExecutionTargets (Solution solution, ConfigurationSelector configuration) @@ -81,6 +108,16 @@ namespace MonoDevelop.Projects return next.GetExecutionTargets (solution, configuration); } + internal protected virtual IEnumerable<ExecutionTarget> GetExecutionTargets (Solution solution, ConfigurationSelector configuration, SolutionRunConfiguration runConfiguration) + { + return next.GetExecutionTargets (solution, configuration, runConfiguration); + } + + internal protected virtual IEnumerable<SolutionRunConfiguration> OnGetRunConfigurations () + { + return next.OnGetRunConfigurations (); + } + internal protected virtual bool NeedsBuilding (ConfigurationSelector configuration) { return next.NeedsBuilding (configuration); diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs index 76b8ae90a7..d34bc6f1a7 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs @@ -52,7 +52,7 @@ using System.Collections.Immutable; namespace MonoDevelop.Projects { - public abstract class SolutionItem : SolutionFolderItem, IWorkspaceFileObject, IConfigurationTarget, IBuildTarget, IMSBuildFileObject + public abstract class SolutionItem : SolutionFolderItem, IWorkspaceFileObject, IConfigurationTarget, IBuildTarget, IMSBuildFileObject, IRunTarget { internal object MemoryProbe = Counters.ItemsInMemory.CreateMemoryProbe (); @@ -72,6 +72,7 @@ namespace MonoDevelop.Projects public event ConfigurationEventHandler DefaultConfigurationChanged; public event ConfigurationEventHandler ConfigurationAdded; public event ConfigurationEventHandler ConfigurationRemoved; + public EventHandler RunConfigurationsChanged; // When set, it means this item is saved as part of a global solution save operation internal bool SavingSolution { get; set; } @@ -394,6 +395,8 @@ namespace MonoDevelop.Projects protected virtual void OnInitializeFromTemplate (ProjectCreateInformation projectCreateInfo, XmlElement template) { + if (projectCreateInfo.TemplateInitializationCallback != null) + projectCreateInfo.TemplateInitializationCallback (this); } protected sealed override FilePath GetDefaultBaseDirectory ( ) @@ -486,12 +489,17 @@ namespace MonoDevelop.Projects return ItemExtension.OnGetSupportedFeatures ().HasFlag (ProjectFeatures.Configurations); } + public bool SupportsRunConfigurations () + { + return ItemExtension.OnGetSupportedFeatures ().HasFlag (ProjectFeatures.RunConfigurations); + } + protected virtual ProjectFeatures OnGetSupportedFeatures () { if (IsUnsupportedProject) return ProjectFeatures.Configurations; else - return ProjectFeatures.Execute | ProjectFeatures.Build | ProjectFeatures.Configurations; + return ProjectFeatures.Execute | ProjectFeatures.Build | ProjectFeatures.Configurations | ProjectFeatures.RunConfigurations; } /// <summary> @@ -822,7 +830,6 @@ namespace MonoDevelop.Projects protected virtual void OnGetProjectEventMetadata (IDictionary<string, string> metadata) { } - /// <summary> /// Executes this solution item /// </summary> @@ -835,7 +842,27 @@ namespace MonoDevelop.Projects /// <param name='configuration'> /// Configuration to use to execute the item /// </param> - public async Task Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) + public Task Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) + { + return Execute (monitor, context, configuration, GetDefaultRunConfiguration ()); + } + + /// <summary> + /// Executes this solution item + /// </summary> + /// <param name='monitor'> + /// A progress monitor + /// </param> + /// <param name='context'> + /// An execution context + /// </param> + /// <param name='configuration'> + /// Configuration to use to execute the item + /// </param> + /// <param name='runConfiguration'> + /// Run configuration to use to execute the item + /// </param> + public async Task Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) { SolutionItemConfiguration conf = GetConfiguration (configuration) as SolutionItemConfiguration; if (conf != null) { @@ -850,7 +877,7 @@ namespace MonoDevelop.Projects if (monitor.CancellationToken.IsCancellationRequested) return; - await ItemExtension.OnExecute (monitor, context, configuration); + await ItemExtension.OnExecute (monitor, context, configuration, runConfiguration ?? GetDefaultRunConfiguration ()); if (conf != null && !monitor.CancellationToken.IsCancellationRequested) { ExecutionContext localContext = new ExecutionContext (Runtime.ProcessService.DefaultExecutionHandler, context.ConsoleFactory, context.ExecutionTarget); @@ -860,6 +887,13 @@ namespace MonoDevelop.Projects } } + Task IRunTarget.Execute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, RunConfiguration runConfiguration) + { + if (runConfiguration != null && !(runConfiguration is SolutionItemRunConfiguration)) + throw new ArgumentException ("Invalid configuration type"); + return Execute (monitor, context, configuration, (SolutionItemRunConfiguration)runConfiguration); + } + /// <summary> /// Prepares the target for execution /// </summary> @@ -873,9 +907,35 @@ namespace MonoDevelop.Projects /// there is no guarantee that Execute() will actually be called.</remarks> public Task PrepareExecution (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) { - return BindTask (ct => ItemExtension.OnPrepareExecution (monitor.WithCancellationToken (ct), context, configuration)); + return PrepareExecution (monitor, context, configuration, GetDefaultRunConfiguration ()); + } + + /// <summary> + /// Prepares the target for execution + /// </summary> + /// <returns>The execution.</returns> + /// <param name="monitor">Monitor for tracking progress</param> + /// <param name="context">Execution context</param> + /// <param name="configuration">Configuration to execute</param> + /// <param name='runConfiguration'> + /// Run configuration to use to execute the item + /// </param> + /// <remarks>This method can be called (it is not mandatory) before Execute() to give the target a chance + /// to asynchronously prepare the execution that is going to be done later on. It can be used for example + /// to start the simulator that is going to be used for execution. Calling this method is optional, and + /// there is no guarantee that Execute() will actually be called.</remarks> + public Task PrepareExecution (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) + { + return BindTask (ct => ItemExtension.OnPrepareExecution (monitor.WithCancellationToken (ct), context, configuration, runConfiguration ?? GetDefaultRunConfiguration ())); } + Task IRunTarget.PrepareExecution (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, RunConfiguration runConfiguration) + { + if (runConfiguration != null && !(runConfiguration is SolutionItemRunConfiguration)) + throw new ArgumentException ("Invalid configuration type"); + return PrepareExecution (monitor, context, configuration, (SolutionItemRunConfiguration)runConfiguration); + } + /// <summary> /// Determines whether this solution item can be executed using the specified context and configuration. /// </summary> @@ -890,17 +950,44 @@ namespace MonoDevelop.Projects /// </param> public bool CanExecute (ExecutionContext context, ConfigurationSelector configuration) { - return !IsUnsupportedProject && ItemExtension.OnGetCanExecute (context, configuration); + return CanExecute (context, configuration, GetDefaultRunConfiguration ()); + } + + /// <summary> + /// Determines whether this solution item can be executed using the specified context and configuration. + /// </summary> + /// <returns> + /// <c>true</c> if this instance can be executed; otherwise, <c>false</c>. + /// </returns> + /// <param name='context'> + /// An execution context + /// </param> + /// <param name='configuration'> + /// Configuration to use to execute the item + /// </param> + /// <param name='runConfiguration'> + /// Run configuration to use to execute the item + /// </param> + public bool CanExecute (ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) + { + return !IsUnsupportedProject && ItemExtension.OnGetCanExecute (context, configuration, runConfiguration ?? GetDefaultRunConfiguration ()); } - async Task DoExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) + bool IRunTarget.CanExecute (ExecutionContext context, ConfigurationSelector configuration, RunConfiguration runConfiguration) + { + if (runConfiguration != null && !(runConfiguration is SolutionItemRunConfiguration)) + throw new ArgumentException ("Invalid configuration type"); + return CanExecute (context, configuration, (SolutionItemRunConfiguration)runConfiguration); + } + + async Task DoExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) { SolutionItemConfiguration conf = GetConfiguration (configuration) as SolutionItemConfiguration; if (conf != null && conf.CustomCommands.HasCommands (CustomCommandType.Execute)) { await conf.CustomCommands.ExecuteCommand (monitor, this, CustomCommandType.Execute, context, configuration); return; } - await OnExecute (monitor, context, configuration); + await OnExecute (monitor, context, configuration, runConfiguration); } /// <summary> @@ -915,6 +1002,14 @@ namespace MonoDevelop.Projects /// <param name='configuration'> /// Configuration to use to execute the item /// </param> + protected virtual Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) + { +#pragma warning disable 618 // Type or member is obsolete + return OnExecute (monitor, context, configuration); +#pragma warning restore 618 // Type or member is obsolete + } + + [Obsolete ("Use overload that takes a RunConfiguration")] protected virtual Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) { return Task.FromResult (0); @@ -927,21 +1022,30 @@ namespace MonoDevelop.Projects /// <param name="monitor">Monitor for tracking progress</param> /// <param name="context">Execution context</param> /// <param name="configuration">Configuration to execute</param> + /// <param name="runConfiguration">Run configuration to execute</param> /// <remarks>This method can be called (it is not mandatory) before Execute() to give the target a chance /// to asynchronously prepare the execution that is going to be done later on. It can be used for example /// to start the simulator that is going to be used for execution. Calling this method is optional, and /// there is no guarantee that Execute() will actually be called.</remarks> + protected virtual Task OnPrepareExecution (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) + { +#pragma warning disable 618 // Type or member is obsolete + return OnPrepareExecution (monitor, context, configuration); +#pragma warning restore 618 // Type or member is obsolete + } + + [Obsolete ("Use overload that takes a RunConfiguration")] protected virtual Task OnPrepareExecution (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) { return Task.FromResult (true); } - protected virtual bool DoGetCanExecute (ExecutionContext context, ConfigurationSelector configuration) + bool DoGetCanExecute (ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) { SolutionItemConfiguration conf = GetConfiguration (configuration) as SolutionItemConfiguration; if (conf != null && conf.CustomCommands.HasCommands (CustomCommandType.Execute)) return conf.CustomCommands.CanExecute (this, CustomCommandType.Execute, context, configuration); - return OnGetCanExecute (context, configuration); + return OnGetCanExecute (context, configuration, runConfiguration); } /// <summary> @@ -956,6 +1060,17 @@ namespace MonoDevelop.Projects /// <param name='configuration'> /// Configuration to use to execute the item /// </param> + /// <param name='runConfiguration'> + /// Run configuration to use to execute the item + /// </param> + protected virtual bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) + { +#pragma warning disable 618 // Type or member is obsolete + return OnGetCanExecute (context, configuration); +#pragma warning restore 618 // Type or member is obsolete + } + + [Obsolete ("Use overload that takes a RunConfiguration")] protected virtual bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration) { SolutionItemConfiguration conf = GetConfiguration (configuration) as SolutionItemConfiguration; @@ -971,10 +1086,32 @@ namespace MonoDevelop.Projects /// <param name="configuration">The configuration.</param> public IEnumerable<ExecutionTarget> GetExecutionTargets (ConfigurationSelector configuration) { + return ItemExtension.OnGetExecutionTargets (new OperationContext (), configuration, GetDefaultRunConfiguration ()); + } + + /// <summary> + /// Gets the execution targets. + /// </summary> + /// <returns>The execution targets.</returns> + /// <param name="configuration">The configuration.</param> + public IEnumerable<ExecutionTarget> GetExecutionTargets (ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) + { + return ItemExtension.OnGetExecutionTargets (new OperationContext (), configuration, runConfiguration ?? GetDefaultRunConfiguration ()); + } + + IEnumerable<ExecutionTarget> IRunTarget.GetExecutionTargets (ConfigurationSelector configuration, RunConfiguration runConfiguration) + { + if (runConfiguration != null && !(runConfiguration is SolutionItemRunConfiguration)) + throw new ArgumentException ("Invalid configuration type"); + return GetExecutionTargets (configuration, (SolutionItemRunConfiguration)runConfiguration); + } + + protected virtual IEnumerable<ExecutionTarget> OnGetExecutionTargets (ConfigurationSelector configuration, SolutionItemRunConfiguration runConfig) + { return ItemExtension.OnGetExecutionTargets (configuration); } - protected void NotifyExecutionTargetsChanged () + public void NotifyExecutionTargetsChanged () { ItemExtension.OnExecutionTargetsChanged (); } @@ -987,6 +1124,49 @@ namespace MonoDevelop.Projects ExecutionTargetsChanged (this, EventArgs.Empty); } + /// <summary> + /// Gets the run configurations. + /// </summary> + /// <returns>The execution targets.</returns> + public IEnumerable<SolutionItemRunConfiguration> GetRunConfigurations () + { + return ItemExtension.OnGetRunConfigurations (new OperationContext ()); + } + + IEnumerable<RunConfiguration> IRunTarget.GetRunConfigurations () + { + return GetRunConfigurations (); + } + + /// <summary> + /// Gets the default run configuration for this item. + /// </summary> + /// <returns>The configuration.</returns> + public SolutionItemRunConfiguration GetDefaultRunConfiguration () + { + var configs = GetRunConfigurations (); + return configs.FirstOrDefault (s => s.IsDefaultConfiguration) ?? configs.FirstOrDefault (); + } + + public void NotifyRunConfigurationsChanged () + { + ItemExtension.OnRunConfigurationsChanged (new OperationContext ()); + if (ParentSolution != null) + ParentSolution.NotifyRunConfigurationsChanged (); + } + + protected virtual void OnRunConfigurationsChanged () + { + if (RunConfigurationsChanged != null) + RunConfigurationsChanged (this, EventArgs.Empty); + } + + protected virtual IEnumerable<SolutionItemRunConfiguration> OnGetRunConfigurations () + { + yield break; + } + + protected virtual Task OnLoad (ProgressMonitor monitor) { return Task.FromResult (0); @@ -1358,19 +1538,19 @@ namespace MonoDevelop.Projects return Item.OnGetSupportedFeatures (); } - internal protected override Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) + internal protected override Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) { - return Item.DoExecute (monitor, context, configuration); + return Item.DoExecute (monitor, context, configuration, runConfiguration); } - internal protected override Task OnPrepareExecution (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) + internal protected override Task OnPrepareExecution (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) { - return Item.OnPrepareExecution (monitor, context, configuration); + return Item.OnPrepareExecution (monitor, context, configuration, runConfiguration); } - internal protected override bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration) + internal protected override bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) { - return Item.DoGetCanExecute (context, configuration); + return Item.DoGetCanExecute (context, configuration, runConfiguration); } internal protected override IEnumerable<ExecutionTarget> OnGetExecutionTargets (ConfigurationSelector configuration) @@ -1378,11 +1558,26 @@ namespace MonoDevelop.Projects yield break; } + internal protected override IEnumerable<ExecutionTarget> OnGetExecutionTargets (OperationContext ctx, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfig) + { + return Item.OnGetExecutionTargets (configuration, runConfig); + } + internal protected override void OnExecutionTargetsChanged () { Item.OnExecutionTargetsChanged (); } + internal protected override IEnumerable<SolutionItemRunConfiguration> OnGetRunConfigurations (OperationContext ctx) + { + return Item.OnGetRunConfigurations (); + } + + internal protected override void OnRunConfigurationsChanged (OperationContext ctx) + { + Item.OnRunConfigurationsChanged (); + } + internal protected override void OnReloadRequired (SolutionItemEventArgs args) { Item.DoOnReloadRequired (args); diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemExtension.cs index ee20bd4c5a..4f9e087975 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemExtension.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemExtension.cs @@ -210,19 +210,46 @@ namespace MonoDevelop.Projects #region Execution + [Obsolete ("Use overload that takes a RunConfiguration")] internal protected virtual Task OnPrepareExecution (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) { - return next.OnPrepareExecution (monitor, context, configuration); + return next.OnPrepareExecution (monitor, context, configuration, (SolutionItemRunConfiguration)context.RunConfiguration); } + [Obsolete ("Use overload that takes a RunConfiguration")] internal protected virtual Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) { - return next.OnExecute (monitor, context, configuration); + return next.OnExecute (monitor, context, configuration, (SolutionItemRunConfiguration)context.RunConfiguration); } + [Obsolete ("Use overload that takes a RunConfiguration")] internal protected virtual bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration) { - return next.OnGetCanExecute (context, configuration); + return next.OnGetCanExecute (context, configuration, (SolutionItemRunConfiguration)context.RunConfiguration); + } + + internal protected virtual Task OnPrepareExecution (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) + { + context.RunConfiguration = runConfiguration; +#pragma warning disable 618 // Type or member is obsolete + return OnPrepareExecution (monitor, context, configuration); +#pragma warning restore 618 // Type or member is obsolete + } + + internal protected virtual Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) + { + context.RunConfiguration = runConfiguration; +#pragma warning disable 618 // Type or member is obsolete + return OnExecute (monitor, context, configuration); +#pragma warning restore 618 // Type or member is obsolete + } + + internal protected virtual bool OnGetCanExecute (ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) + { + context.RunConfiguration = runConfiguration; +#pragma warning disable 618 // Type or member is obsolete + return OnGetCanExecute (context, configuration); +#pragma warning restore 618 // Type or member is obsolete } internal protected virtual IEnumerable<ExecutionTarget> OnGetExecutionTargets (ConfigurationSelector configuration) @@ -230,11 +257,26 @@ namespace MonoDevelop.Projects return next.OnGetExecutionTargets (configuration); } + internal protected virtual IEnumerable<ExecutionTarget> OnGetExecutionTargets (OperationContext ctx, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfig) + { + return next.OnGetExecutionTargets (ctx, configuration, runConfig); + } + internal protected virtual void OnExecutionTargetsChanged () { next.OnExecutionTargetsChanged (); } + internal protected virtual IEnumerable<SolutionItemRunConfiguration> OnGetRunConfigurations (OperationContext ctx) + { + return next.OnGetRunConfigurations (ctx); + } + + internal protected virtual void OnRunConfigurationsChanged (OperationContext ctx) + { + next.OnRunConfigurationsChanged (ctx); + } + #endregion #region Events diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemRunConfiguration.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemRunConfiguration.cs new file mode 100644 index 0000000000..4118baf8d4 --- /dev/null +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItemRunConfiguration.cs @@ -0,0 +1,72 @@ +// +// RunConfiguration.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 MonoDevelop.Core.Execution; + +namespace MonoDevelop.Projects +{ + public class SolutionItemRunConfiguration: RunConfiguration + { + string id; + string name; + + public SolutionItemRunConfiguration (string id) + { + this.name = this.id = id; + } + + public SolutionItemRunConfiguration (string id, string name) + { + this.id = id; + this.name = name; + } + + public SolutionItem ParentItem { + get; + internal set; + } + + public sealed override string Name { + get { return name; } + } + + public sealed override string Id { + get { return id; } + } + + public override string ToString () + { + return Name; + } + + public bool IsDefaultConfiguration { + get { return Id == "Default"; } + } + + public ExecutionTarget ExecutionTarget { get; set; } + } +} + diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionRunConfiguration.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionRunConfiguration.cs new file mode 100644 index 0000000000..1e0d693b37 --- /dev/null +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionRunConfiguration.cs @@ -0,0 +1,66 @@ +// +// SolutionRunConfiguration.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; +namespace MonoDevelop.Projects +{ + public class SolutionRunConfiguration: RunConfiguration + { + string id; + string name; + + public SolutionRunConfiguration (string id) + { + this.name = this.id = id; + } + + public SolutionRunConfiguration (string id, string name) + { + this.id = id; + this.name = name; + } + + internal Solution ParentSolution { get; set; } + + public sealed override string Name { + get { return name; } + } + + public sealed override string Id { + get { return id; } + } + + protected void SetName (string name) + { + this.name = name; + } + + public override string ToString () + { + return Name; + } + } +} + diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionRunConfigurationCollection.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionRunConfigurationCollection.cs new file mode 100644 index 0000000000..3e7e6a3da2 --- /dev/null +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionRunConfigurationCollection.cs @@ -0,0 +1,65 @@ +// +// RunConfigurationCollection.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; + +namespace MonoDevelop.Projects +{ + public class SolutionRunConfigurationCollection: ItemCollection<SolutionRunConfiguration> + { + Solution parentSolution; + + public SolutionRunConfigurationCollection () + { + } + + internal SolutionRunConfigurationCollection (Solution parentSolution) + { + this.parentSolution = parentSolution; + } + + protected override void OnItemsAdded (IEnumerable<SolutionRunConfiguration> items) + { + if (parentSolution != null) { + foreach (var conf in items) + conf.ParentSolution = parentSolution; + } + base.OnItemsAdded (items); + parentSolution.OnRunConfigurationsAdded (items); + } + + protected override void OnItemsRemoved (IEnumerable<SolutionRunConfiguration> items) + { + if (parentSolution != null) { + foreach (var conf in items) + conf.ParentSolution = null; + } + base.OnItemsRemoved (items); + parentSolution.OnRunConfigurationRemoved (items); + } + } +} + diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownProject.cs index e37bd6b611..77f9ae4bbc 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownProject.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/UnknownProject.cs @@ -93,7 +93,7 @@ namespace MonoDevelop.Projects return Task.FromResult (r); } - protected override Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration) + protected override Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration) { return new Task (delegate { }); |