Задача MSBuild exec без блокировки
Кто-нибудь случайно узнает трюк, который заставит эту задачу MSBuild блокироваться? Я просто хочу, чтобы проводник был открыт, а сборка script продолжалась. В настоящее время он блокируется в задаче Exec до закрытия окна проводника.
<Target Name="OpenExplorer">
<Exec Command='explorer.exe "$(DestinationDir)"' IgnoreExitCode="true" />
</Target>
Спасибо!
Изменить: Я надеялся избежать создания настраиваемой задачи для этого. Возможно, существует какая-то маска командной строки, которая может быть встроена в строку Command
?
Ответы
Ответ 1
Вы не можете сделать это с помощью native Exec
. Но вы можете написать свой собственный, который срабатывает асинхронно, как в в этом примере:
public class AsyncExec : Exec {
protected override int ExecuteTool(string pathToTool,
string responseFileCommands,
string commandLineCommands) {
Process process = new Process();
process.StartInfo = GetProcessStartInfo(pathToTool, commandLineCommands);
process.Start();
return 0;
}
protected virtual ProcessStartInfo GetProcessStartInfo(string executable,
string arguments) {
if (arguments.Length > 0x7d00) {
this.Log.LogWarningWithCodeFromResources("ToolTask.CommandTooLong", new object[] { base.GetType().Name });
}
ProcessStartInfo startInfo = new ProcessStartInfo(executable, arguments);
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = true;
string workingDirectory = this.GetWorkingDirectory();
if (workingDirectory != null) {
startInfo.WorkingDirectory = workingDirectory;
}
StringDictionary environmentOverride = this.EnvironmentOverride;
if (environmentOverride != null) {
foreach (DictionaryEntry entry in environmentOverride) {
startInfo.EnvironmentVariables.Remove(entry.Key.ToString());
startInfo.EnvironmentVariables.Add(entry.Key.ToString(), entry.Value.ToString());
}
}
return startInfo;
}
}
который вы можете запустить с помощью:
<AsyncExec Command="..." />
Ответ 2
Вот простой способ выполнения процессов асинхронно, используя только команды msbuild и встроенные задачи. Это только для MSBuild V4.0 и выше (Бог благословит ребята из MSBuild, добавив эту функцию!). Вам не нужны внешние пакеты расширения.
Эффективно мы берем предложенный выше код и помещаем его в встроенную задачу. Не стесняйтесь писать код, чтобы удовлетворить ваши потребности.
Точка этого решения состоит в том, что он позволяет достичь результата без головной боли при создании отдельной dll для настраиваемой задачи. Реализация в расширительном пакете определенно более прочная, но это работает как быстрый "грязный способ решения этой проблемы". Вы также можете настроить именно то, как вы хотите его запустить.
<!--Launch a Process in Parallel-->
<UsingTask TaskName="ExecAsync" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
<ParameterGroup>
<!--The file path is the full path to the executable file to run-->
<FilePath ParameterType="System.String" Required="true" />
<!--The arguments should contain all the command line arguments that need to be sent to the application-->
<Arguments ParameterType="System.String" Required="true" />
</ParameterGroup>
<Task>
<Code Type="Fragment" Language="cs">
<![CDATA[
string name = System.IO.Path.GetFileNameWithoutExtension(FilePath);
Log.LogMessage("Starting {0}...", name);
System.Diagnostics.ProcessStartInfo processStartInfo = new System.Diagnostics.ProcessStartInfo(FilePath, Arguments);
processStartInfo.UseShellExecute = true;
System.Diagnostics.Process.Start(processStartInfo);
Log.LogMessage("Finished running process {0}.", name);
]]>
</Code>
</Task>
</UsingTask>
Затем вы можете вызвать задачу ExecAsync из вашего обычного script следующим образом. Примечание. Мой script ниже используется для сбора покрытия кода для приложения.
<!--Start listening for coverage data:-->
<Message Text="Starting to listen for coverage..."/>
<ExecAsync FilePath='$(VSPerfCmdExePath)' Arguments='/start:coverage /output:"$(CoverageFilePath)"' ContinueOnError='true'/>
<Message Text="Listening for coverage..."/>
<!--Start App with Coverage:-->
<Message Text="Starting App..."/>
<Exec Command='"$(AppCoverageLatestExePath)"' ContinueOnError='true' WorkingDirectory='$(AppCoverageLatestFolder)'/>
<Message Text="App shut down."/>
<!--Stop gathering coverage results:-->
<Message Text="Stopping listening for coverage..."/>
<Exec Command='"$(VSPerfCmdExePath)" /shutdown'/>
<Message Text="Coverage shut down."/>
Вот описание того, что там происходит:
- Сначала я удаляю инструмент исполнения, чтобы он слушал
охват. Я делаю это, используя нашу задачу AsyncExec, потому что обычно
блоков инструментов при работе в MSBuild (см. здесь).
- Затем мы начинаем нашу программу, которую хотим получить на сайте.
- Затем мы завершим инструмент покрытия, как только мы закончим.
Ответ 3
Отвечено на Запуск программы с проектом MSBuild/Web Deployment Project и не дожидаться ее
<Exec Command="..." Timeout="2000"></Exec>
Ответ 4
Попробуйте AsyncExec в MSBuild Extension Pack.
Ответ 5
Команда в Exec помещается в пакетный файл и выполняется. Таким образом, вы можете использовать ключевое слово "start" в команде так же, как в окне консоли. Это сделает трюк.