2015-12-11 2 views
1

У меня есть цель MSBuild, которая запускает задачу Exec для нескольких элементов. Как получить код выхода для каждого из них?Как получить выходной параметр MSBuild для каждого выполнения пакетной задачи?

я могу использовать это, чтобы получить все коды выхода и работать только, если входные файлы были изменены с момента последнего запуска (т.е. дополнительных сборок):

<ItemGroup> 
    <TestItem Include="MyFile1" /> 
    <TestItem Include="MyFile2" /> 
    <TestItem Include="MyFile10" /> 
</ItemGroup> 

<Target Name="PrepareItemTest"> 
    <ItemGroup> 
     <TestItem> 
      <!-- The timestamp of the "done file" is used below to detect if this target has been run since the inputs have been modified. --> 
      <DoneFilePath>%(TestItem.RelativeDir)%(TestItem.Filename).done/DoneFilePath> 
     </TestItem> 
    </ItemGroup> 
</Target> 

<Target Name="ItemTest" 
     DependsOnTargets="PrepareItemTest" 
     Inputs="@(TestItem);@(OtherInputs)" 
     Outputs="%(TestItem.DoneFilePath)"> 

    <Exec Command="ECHO Running on %(TestItem.Identity) |findstr 1" IgnoreExitCode="true"> 
     <Output TaskParameter="ExitCode" PropertyName="TestExitCode"/> 
    </Exec> 

    <Error Condition=" '$(TestExitCode)' != '0' " Text="Error $TestExitCode" /> 
    <WriteLinesToFile Condition=" '$(TestExitCode)' == '0' " File="%(TestItem.DoneFilePath)" Lines="Ran successfully on %(TestItem.Filename)%(TestItem.Extension)" /> 
</Target> 

Выход:

Ran ItemTest. Exit code=0 
Ran ItemTest. Exit code=1 

Таким образом, это печатает все возвращаемые коды возврата, но не связывает их с элементом ввода, поэтому я не знаю, какие входы были обработаны успешно, а какие нет.

+1

см. Http://stackoverflow.com/questions/7420812/add-custom-metadata-to-already-defined-itemgroup-from-another-itemgroup, например, который делает именно то, что вы хотите (просто использует ReadLines для получения выход вместо exexe, но принцип тот же) – stijn

ответ

1

Самый простой способ достичь этого - batch по сравнению с мишенью, а не самой задачей. Это эффективно «перемещает петлю на уровень вверх», от (псевдокод):

target PrepareItemTest { 
    foreach item in TestItem { 
     TestExitCode.append(exec().result)) 
    } 
    warn("exit codes: " + TestExitCode) 
} 

к

target PrepareItemTest { 
    foreach item in TestItem { 
     TestExitCode.append(exec().result)) 
     warn("exit code: " item + " " + TestExitCode) 
    } 
} 

Если элементы представляют собой файлы, которые производят выходы, это просто, и вы должны партия в Inputs (и определите Outputs для правильного инкрементного поведения).

Для примера, который вы указали, он немного запутан, потому что цель не создает набор выходных файлов. Это означает, что вы должны злоупотреблять атрибутом цели Outputs, чтобы получить поведение дозирования. Вы можете сделать:

<Target Name="ItemTest" Outputs="%(TestItem.Identity)"> 
    <Exec Command="ECHO Running on @(TestItem->'%(Identity)') |findstr 1" IgnoreExitCode="true"> 
     <Output TaskParameter="ExitCode" PropertyName="TestExitCode"/> 
    </Exec> 

    <Warning Text="Ran ItemTest for @(TestItem). Exit code=$(TestExitCode)" /> 
</Target> 

Который производит

Project "D:\work\batch-over-target.proj" on node 1 (default targets). 
ItemTest: 
    ECHO Running on MyItem1 |findstr 1 
    Running on MyItem1 
D:\work\batch-over-target.proj(14,5): warning : Ran ItemTest for MyItem1. Exit code=0 
ItemTest: 
    ECHO Running on MyItem2 |findstr 1 
    The command "ECHO Running on MyItem2 |findstr 1" exited with code 1. 
D:\work\batch-over-target.proj(14,5): warning : Ran ItemTest for MyItem2. Exit code=1 
ItemTest: 
    ECHO Running on MyItem10 |findstr 1 
    Running on MyItem10 
D:\work\batch-over-target.proj(14,5): warning : Ran ItemTest for MyItem10. Exit code=0 
Done Building Project "D:\work\batch-over-target.proj" (default targets). 

Причина этого в том, что работает в пакетном режиме, элемент доступен с @(ItemName) включает только результаты, которые соответствуют в партии. Если вы тщательно следите за тем, чтобы каждая партия была только одним элементом, вы можете сопоставить выходы с входами.

+0

Так что в основном это вопрос добавления 'Outputs ="% (TestItem.Identity) "'? Это хороший трюк, спасибо! Единственная проблема заключается в том, что моя реальная цель уже имеет Output set, чтобы включить инкрементное построение, поэтому я полагаю, что мне придется поставить задачу Exec в подцель и вызвать ее с помощью задачи MSBuild. – EM0

+0

В этой ситуации я бы не рекомендовал использовать задачу MSBuild, потому что, чтобы иметь возможность вызывать ее несколько раз, вам придется изменить глобальные свойства, которые являются опасными. Однако вы должны быть в состоянии избежать этого. Можете ли вы обновить вопрос, чтобы цель выглядела немного больше, чем ваш настоящий? Бьюсь об заклад, есть способ заставить его работать вместе. –

+0

ОК, я отредактировал вопрос. В основном я хочу поддерживать инкрементные сборки, только запуская задачу Exec, когда выход старше ввода. Я пишу однострочный текстовый файл в конце цели, который действует как «выход». – EM0

Смежные вопросы