Imported Upstream version 3.10.0

Former-commit-id: 172c8e3c300b39d5785c7a3e8dfb08ebdbc1a99b
This commit is contained in:
Jo Shields
2014-10-04 11:27:48 +01:00
parent fe777c5c82
commit 8b9b85e7f5
970 changed files with 20242 additions and 31308 deletions

View File

@ -78,43 +78,38 @@ namespace Microsoft.Build.BuildEngine {
if (propertyName != null)
element.SetAttribute ("PropertyName", propertyName);
}
[MonoTODO]
public bool Execute ()
{
bool result = false;
TaskEngine taskEngine;
LogTaskStarted ();
ITask task = null;
ITask task;
try {
try {
task = InitializeTask ();
} catch (Exception e) {
LogError ("Error initializing task {0}: {1}", taskElement.LocalName, e.Message);
LogMessage (MessageImportance.Low, "Error initializing task {0}: {1}",
taskElement.LocalName, e.ToString ());
return false;
}
try {
taskEngine = new TaskEngine (parentTarget.Project);
taskEngine.Prepare (task, this.taskElement, GetParameters (), this.Type);
result = taskEngine.Execute ();
if (result)
taskEngine.PublishOutput ();
} catch (Exception e) {
task_logger.LogError ("Error executing task {0}: {1}", taskElement.LocalName, e.Message);
task_logger.LogMessage (MessageImportance.Low,
"Error executing task {0}: {1}", taskElement.LocalName, e.ToString ());
result = false;
}
} finally {
LogTaskFinished (result);
task = InitializeTask ();
} catch (Exception e) {
LogError ("Error initializing task {0}: {1}", taskElement.LocalName, e.Message);
LogMessage (MessageImportance.Low, "Error initializing task {0}: {1}",
taskElement.LocalName, e.ToString ());
return false;
}
return result;
try {
taskEngine = new TaskEngine (parentTarget.Project, task, Type);
taskEngine.Prepare (GetParameters ());
var result = taskEngine.Execute ();
if (result)
taskEngine.PublishOutput (taskElement, taskEngine.ValueFromExecution);
LogTaskFinished (result);
return result;
} catch (Exception e) {
task_logger.LogError ("Error executing task {0}: {1}", taskElement.LocalName, e.Message);
task_logger.LogMessage (MessageImportance.Low,
"Error executing task {0}: {1}", taskElement.LocalName, e.ToString ());
return false;
}
}
@ -140,6 +135,21 @@ namespace Microsoft.Build.BuildEngine {
return taskElement.GetAttribute (attributeName);
}
bool IBuildTask.ResolveOutputItems ()
{
var taskEngine = new TaskEngine (parentTarget.Project, null, Type);
taskEngine.PublishOutput (taskElement, l => {
var pv = GetParameterValue (l.Name);
Expression exp = new Expression ();
exp.Parse (pv, ParseOptions.AllowItemsMetadataAndSplit);
return exp.ConvertTo (parentTarget.Project, l.PropertyType);
});
return true;
}
public void SetParameterValue (string parameterName,
string parameterValue)

View File

@ -73,6 +73,11 @@ namespace Microsoft.Build.BuildEngine
foreach (XmlAttribute attrib in XmlElement.Attributes)
yield return attrib.Value;
}
public bool ResolveOutputItems ()
{
return true;
}
}
}

View File

@ -52,7 +52,11 @@ namespace Microsoft.Build.BuildEngine {
{
return GetAttributes ();
}
public bool ResolveOutputItems ()
{
return true;
}
}
}

View File

@ -38,6 +38,7 @@ namespace Microsoft.Build.BuildEngine {
}
bool Execute ();
bool ResolveOutputItems ();
IEnumerable<string> GetAttributes ();
}

View File

@ -36,7 +36,6 @@ using System.Xml;
using Microsoft.Build.Framework;
namespace Microsoft.Build.BuildEngine {
internal class TargetBatchingImpl : BatchingImplBase
{
string inputs;
@ -58,17 +57,6 @@ namespace Microsoft.Build.BuildEngine {
{
executeOnErrors = false;
try {
string reason;
if (!BuildTargetNeeded (out reason)) {
LogTargetStarted (target);
LogTargetSkipped (target, reason);
LogTargetFinished (target, true);
return true;
}
if (!String.IsNullOrEmpty (reason))
target.Engine.LogMessage (MessageImportance.Low, reason);
Init ();
ParseTargetAttributes (target);
@ -104,24 +92,52 @@ namespace Microsoft.Build.BuildEngine {
executeOnErrors = false;
LogTargetStarted (target);
if (bucket != null)
project.PushBatch (bucket, commonItemsByName);
try {
string reason;
if (!BuildTargetNeeded (out reason)) {
LogTargetSkipped (target, reason);
return true;
}
if (!String.IsNullOrEmpty (reason))
target.Engine.LogMessage (MessageImportance.Low, reason);
try {
TaskExecutionMode taskExecutionMode;
string reason;
bool skip_completely;
if (!BuildTargetNeeded (out reason, out skip_completely)) {
LogTargetSkipped (target, reason);
if (skip_completely)
return true;
taskExecutionMode = TaskExecutionMode.SkipAndSetOutput;
} else {
taskExecutionMode = TaskExecutionMode.Complete;
if (!String.IsNullOrEmpty (reason))
target.Engine.LogMessage (MessageImportance.Low, reason);
}
for (int i = 0; i < target.BuildTasks.Count; i ++) {
//FIXME: parsing attributes repeatedly
IBuildTask bt = target.BuildTasks [i];
// HACK: need some form of cross references checks
var tem = taskExecutionMode;
if (tem == TaskExecutionMode.SkipAndSetOutput) {
var bti = bt as BuildTask;
//
// BuildTargetNeeded checks only files timestamps but ignores any metadata dependencies
// that way we can end up in the situation when output metadata are populated but from
// incomplete dependencies.
//
// E.g.
// <CreateItem Include="$(IntermediateOutputPath)%(_PngImage.LogicalName)" AdditionalMetadata="LogicalName=%(_PngImage.LogicalName)">
// <Output TaskParameter="Include" />
// </CreateItem>
//
if (bti != null && bti.Name == "CreateItem")
tem = TaskExecutionMode.Complete;
}
TaskBatchingImpl batchingImpl = new TaskBatchingImpl (project);
bool task_result = batchingImpl.Build (bt, out executeOnErrors);
bool task_result = batchingImpl.Build (bt, tem, out executeOnErrors);
if (task_result)
continue;
@ -138,6 +154,7 @@ namespace Microsoft.Build.BuildEngine {
} finally {
if (bucket != null)
project.PopBatch ();
LogTargetFinished (target, target_result);
}
@ -155,15 +172,17 @@ namespace Microsoft.Build.BuildEngine {
ParseAttribute (outputs);
}
bool BuildTargetNeeded (out string reason)
bool BuildTargetNeeded (out string reason, out bool skipCompletely)
{
reason = String.Empty;
ITaskItem [] inputFiles;
ITaskItem [] outputFiles;
DateTime youngestInput, oldestOutput;
skipCompletely = false;
if (String.IsNullOrEmpty (inputs.Trim ()))
if (String.IsNullOrEmpty (inputs.Trim ())) {
return true;
}
if (String.IsNullOrEmpty (outputs.Trim ())) {
project.ParentEngine.LogError ("Target {0} has inputs but no outputs specified.", name);
@ -184,6 +203,7 @@ namespace Microsoft.Build.BuildEngine {
}
if (inputFiles == null || inputFiles.Length == 0) {
skipCompletely = true;
reason = String.Format ("No input files were specified for target {0}, skipping.", name);
return false;
}

View File

@ -40,7 +40,7 @@ namespace Microsoft.Build.BuildEngine {
{
}
public bool Build (IBuildTask buildTask, out bool executeOnErrors)
public bool Build (IBuildTask buildTask, TaskExecutionMode taskExecutionMode, out bool executeOnErrors)
{
executeOnErrors = false;
try {
@ -49,15 +49,11 @@ namespace Microsoft.Build.BuildEngine {
// populate list of referenced items and metadata
ParseTaskAttributes (buildTask);
if (consumedMetadataReferences.Count == 0) {
// No batching required
if (ConditionParser.ParseAndEvaluate (buildTask.Condition, project))
return buildTask.Execute ();
else // skipped, it should be logged
return true;
return Execute (buildTask, taskExecutionMode);
}
BatchAndPrepareBuckets ();
return Run (buildTask, out executeOnErrors);
return Run (buildTask, taskExecutionMode, out executeOnErrors);
} finally {
consumedItemsByName = null;
consumedMetadataReferences = null;
@ -68,7 +64,7 @@ namespace Microsoft.Build.BuildEngine {
}
}
bool Run (IBuildTask buildTask, out bool executeOnErrors)
bool Run (IBuildTask buildTask, TaskExecutionMode taskExecutionMode, out bool executeOnErrors)
{
executeOnErrors = false;
@ -76,11 +72,9 @@ namespace Microsoft.Build.BuildEngine {
bool retval = true;
if (buckets.Count == 0) {
// batched mode, but no values in the corresponding items!
if (ConditionParser.ParseAndEvaluate (buildTask.Condition, project)) {
retval = buildTask.Execute ();
if (!retval && !buildTask.ContinueOnError)
executeOnErrors = true;
}
retval = Execute (buildTask, taskExecutionMode);
if (!retval && !buildTask.ContinueOnError)
executeOnErrors = true;
return retval;
}
@ -89,12 +83,10 @@ namespace Microsoft.Build.BuildEngine {
foreach (Dictionary<string, BuildItemGroup> bucket in buckets) {
project.PushBatch (bucket, commonItemsByName);
try {
if (ConditionParser.ParseAndEvaluate (buildTask.Condition, project)) {
retval = buildTask.Execute ();
if (!retval && !buildTask.ContinueOnError) {
executeOnErrors = true;
break;
}
retval = Execute (buildTask, taskExecutionMode);
if (!retval && !buildTask.ContinueOnError) {
executeOnErrors = true;
break;
}
} finally {
project.PopBatch ();
@ -104,6 +96,22 @@ namespace Microsoft.Build.BuildEngine {
return retval;
}
bool Execute (IBuildTask buildTask, TaskExecutionMode taskExecutionMode)
{
if (ConditionParser.ParseAndEvaluate (buildTask.Condition, project)) {
switch (taskExecutionMode) {
case TaskExecutionMode.Complete:
return buildTask.Execute ();
case TaskExecutionMode.SkipAndSetOutput:
return buildTask.ResolveOutputItems ();
default:
throw new NotImplementedException ();
}
}
return true;
}
// Parse task attributes to get list of referenced metadata and items
// to determine batching

View File

@ -38,10 +38,9 @@ using Microsoft.Build.Utilities;
namespace Microsoft.Build.BuildEngine {
internal class TaskEngine {
ITask task;
XmlElement taskElement;
Type taskType;
Project parentProject;
ITask task;
static Type requiredAttribute;
static Type outputAttribute;
@ -52,9 +51,11 @@ namespace Microsoft.Build.BuildEngine {
outputAttribute = typeof (Microsoft.Build.Framework.OutputAttribute);
}
public TaskEngine (Project project)
public TaskEngine (Project project, ITask task, Type taskType)
{
parentProject = project;
this.task = task;
this.taskType = taskType;
}
// Rules (inferred) for property values incase of empty data
@ -69,17 +70,13 @@ namespace Microsoft.Build.BuildEngine {
// string/
// ITaskItem[] empty/whitespace null No
public void Prepare (ITask task, XmlElement taskElement,
IDictionary <string, string> parameters, Type taskType)
public void Prepare (IDictionary <string, string> parameters)
{
Dictionary <string, object> values;
PropertyInfo currentProperty;
PropertyInfo[] properties;
object value;
this.task = task;
this.taskElement = taskElement;
this.taskType = taskType;
values = new Dictionary <string, object> (StringComparer.OrdinalIgnoreCase);
foreach (KeyValuePair <string, string> de in parameters) {
@ -131,20 +128,18 @@ namespace Microsoft.Build.BuildEngine {
InitializeParameter (pi, val);
}
}
public bool Execute ()
{
return task.Execute ();
}
public void PublishOutput ()
public void PublishOutput (XmlElement taskElement, Func<PropertyInfo, object> valueProvider)
{
XmlElement xmlElement;
PropertyInfo propertyInfo;
string propertyName;
string taskParameter;
string itemName;
object o;
foreach (XmlNode xmlNode in taskElement.ChildNodes) {
if (!(xmlNode is XmlElement))
@ -165,16 +160,17 @@ namespace Microsoft.Build.BuildEngine {
taskParameter = xmlElement.GetAttribute ("TaskParameter");
itemName = xmlElement.GetAttribute ("ItemName");
propertyName = xmlElement.GetAttribute ("PropertyName");
propertyInfo = taskType.GetProperty (taskParameter, BindingFlags.Public | BindingFlags.Instance |
BindingFlags.IgnoreCase);
var propertyInfo = taskType.GetProperty (taskParameter, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
if (propertyInfo == null)
throw new InvalidProjectFileException (String.Format (
"The parameter '{0}' was not found for the '{1}' task.", taskParameter, taskElement.Name));
throw new InvalidProjectFileException (String.Format ("The parameter '{0}' was not found for the '{1}' task.", taskParameter, taskElement.Name));
if (!propertyInfo.IsDefined (outputAttribute, false))
throw new InvalidProjectFileException ("This is not output property.");
throw new InvalidProjectFileException ("This is not output property.");
o = propertyInfo.GetValue (task, null);
var o = valueProvider (propertyInfo);
if (itemName != String.Empty) {
PublishItemGroup (propertyInfo, o, itemName);
} else {
@ -260,5 +256,10 @@ namespace Microsoft.Build.BuildEngine {
return true;
}
public object ValueFromExecution (PropertyInfo propertyInfo)
{
return propertyInfo.GetValue (task, null);
}
}
}

View File

@ -0,0 +1,36 @@
//
// TaskExecutionMode.cs
//
// Authors:
// Marek Safar <marek.safar@gmail.com>
//
// Copyright (C) 2014 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.
//
namespace Microsoft.Build.BuildEngine
{
enum TaskExecutionMode
{
Complete = 0,
SkipAndSetOutput = 1
}
}