Оценить элемент, определенный в задаче msbuild через C #

Я пытаюсь сгенерировать ориентированный граф (точечный формат) целей, который будет вызываться с путем к файлу проекта MSBuild в качестве входных данных. Это так же какgrand-ui от ggtools.net (за исключением того, что я пытаюсь использовать изображение только для чтения).

Есть 3 случая, которые я хочу рассмотреть:

1) Цель имеет атрибут DependsOnTargets

2) Цель вызывает MSBuild, используя задачу Exec.

3) Цель вызывает задачу MSBuild и передает ItemGroup.

Я считаю, что я в основном обработал # 1 и # 2 в коде ниже. Однако я не могу понять, как получить ссылку на ItemGroup.

Пример проекта MSBuild:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0" DefaultTargets="Build">
    <Target Name="Build" DependsOnTargets="PrepareEnvironmentForBuild;MapDrives">
        <Exec Command="$(MSBuildBinPath)\msbuild /nologo /clp:Verbosity=quiet $(MSBuildThisFileFullPath) /t:TargetWithConfidentialSteps"/>
        <ItemGroup>
            <StepsToRunInParallel Include="$(MSBuildThisFileFullPath)">
                <Properties>TargetToInvoke=ParallelTarget1</Properties>
            </StepsToRunInParallel>
            <StepsToRunInParallel Include="$(MSBuildThisFileFullPath)">
                <Properties>TargetToInvoke=ParallelTarget2</Properties>
            </StepsToRunInParallel>
        </ItemGroup>
        <MSBuild Projects="@(StepsToRunInParallel)" BuildInParallel="true" StopOnFirstFailure="true" Targets="InvokeInParallelWithinThisProject"/>

    </Target>
    <Target Name="InvokeInParallelWithinThisProject">
        <MSBuild Projects="$(MSBuildThisFileFullPath)" Targets="$(TargetToInvoke)" StopOnFirstFailure="true"/>
    </Target>
    <Target Name="ParallelTarget1">
        <Message Text="Hello from ParallelTarget1"/>
    </Target>
    <Target Name="ParallelTarget2">
        <Message Text="Hello from ParallelTarget2"/>
    </Target>
    <Target Name="PrepareEnvironmentForBuild">
        <Message Text="Hello from PrepareEnvironmentForBuild"/>
    </Target>
    <Target Name="MapDrives">
        <Message Text="Hello from MapDrives"/>
    </Target>
    <Target Name="TargetWithConfidentialSteps">
        <Message Text="Hush! Verbosity on the wrapper does not affect the Exec call." Importance="High"/>
    </Target>

</Project>

Однако цели могут охватывать несколько файлов проекта.

Что мне удалось до сих пор (VS2010 + .NET 4):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Execution;
using Microsoft.Build.Framework;
namespace ConsoleApplication18
{
    class Program
    {
        static String ProcessMSBuildFile(System.IO.FileInfo file, ProjectTaskInstance referringTask = null)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("subgraph cluster_" + file.FullName.Replace(".", "_").Replace(@"\", "_").Replace(":", "_") + " {");
            ProjectInstance currentProj = new ProjectInstance(file.FullName);

            foreach (ProjectTargetInstance target in currentProj.Targets.Values)
            {
                if (String.IsNullOrWhiteSpace(target.DependsOnTargets))
                {
                    sb.AppendLine(target.Name + ";");
                }
                else
                {
                    for (int i = 0; i < target.DependsOnTargets.Split(';').Length; i++)
                    {
                        sb.AppendLine(target.Name + "->" + currentProj.ExpandString(target.DependsOnTargets.Split(';')[i]) + ";");
                    }
                }
                foreach (ProjectTaskInstance task in target.Tasks)
                {
                    if (task.Name == "MSBuild")
                    {
                        foreach (String projectPath in task.Parameters["Projects"].Split(';').AsEnumerable<String>())
                        {
                            if (projectPath.StartsWith("$"))
                            {
                                if (currentProj.ExpandString(projectPath) != currentProj.FullPath)
                                {
                                    sb.Append(ProcessMSBuildFile(new System.IO.FileInfo(currentProj.ExpandString(projectPath))));
                                }
                            }
                            else if (projectPath.StartsWith("@"))
                            {
                                sb.AppendLine("Could not handle : " + projectPath);
                            }

                        }
                        foreach (String msbuildTaskTarget in task.Parameters["Targets"].Split(';'))
                        {
                            if (referringTask != null)
                            {
                                sb.AppendLine(referringTask.Name + "->" + task.Name + ";");
                            }
                            else
                            {
                                sb.AppendLine(task.Name + ";");
                            }
                        }
                    }
                    else if (task.Name == "Exec")
                    {
                        // Get the Command. If it is MSBuild, we should process it further.
                        if (task.Parameters.ContainsKey("Command"))
                        {
                            String taskCommand = currentProj.ExpandString(task.Parameters["Command"]);
                            String executablePath = taskCommand.Substring(0, taskCommand.IndexOf(" "));
                            if (new System.IO.FileInfo(executablePath).Name.ToLower() == "msbuild")
                            {
                                String[] separator = { " " };
                                String projectPath = taskCommand.Split(separator, StringSplitOptions.RemoveEmptyEntries).Where<String>(arg => !arg.StartsWith("/")).ElementAt(1);
                                if (projectPath != currentProj.FullPath)
                                {
                                    ProcessMSBuildFile(new System.IO.FileInfo(projectPath));
                                }
                                else
                                {

                                    foreach (String targetToBeCalled in taskCommand.Split(separator, StringSplitOptions.RemoveEmptyEntries).Where(arg => (arg.ToLower().StartsWith("/t") || arg.ToLower().StartsWith("/target"))))
                                    {
                                        sb.Append(target.Name + "->" + targetToBeCalled.Replace("/target:", "").Replace("/t:", ""));
                                    }

                                }
                            }
                        }
                    }
                }
            }
            sb.AppendLine("}");
            return sb.ToString();
        }
        static void Main(string[] args)
        {
            if (args.Length != 1)
            {
                System.Console.WriteLine("Please pass the path to an MSBuild project as argument.\nPress any key to quit.");
                System.Console.Read();
                return;
            }
            if (!System.IO.File.Exists(args[0]))
            {
                System.Console.WriteLine("Input MSBuild project file does not exist.\nPress any key to quit.");
                System.Console.Read();
                return;
            }
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("digraph Build {");
            sb.Append(ProcessMSBuildFile(new System.IO.FileInfo(args[0])));
            sb.AppendLine("}");
            System.Console.WriteLine(sb);
        }
    }
}

Проблема с разделом «Не удалось обработать».

Что я пытаюсь сгенерировать:

digraph Build {
subgraph cluster_C__temp_proj {
Build->PrepareEnvironmentForBuild;
Build->MapDrives;
Build->TargetWithConfidentialSteps;
Build->InvokeInParallelWithinThisProject;
InvokeInParallelWithinThisProject->ParallelTarget1;
InvokeInParallelWithinThisProject->ParallelTarget2;
InvokeInParallelWithinThisProject;
ParallelTarget1;
ParallelTarget2;
PrepareEnvironmentForBuild;
MapDrives;
TargetWithConfidentialSteps;
}
}

Может кто-нибудь помочь мне получить ссылку на ItemGroup "StepsToRunInParallel" из приведенного выше примера?

Я также подумал о регистрации регистратора, который бы просто записывал:

1) Имя файла проекта для создания кластеров / подграфов

2) Название цели

А затем использовать событие, не выполняя ничего. Любые идеи в этом направлении тоже приветствуются.

Ответы на вопрос(0)

Ваш ответ на вопрос