MSBuild Exec Task без блокировки - PullRequest
15 голосов
/ 05 марта 2010

Может быть, кто-нибудь знает хитрость, которая не позволит этой задаче MSBuild блокироваться? Я действительно хочу, чтобы проводник открылся и скрипт сборки продолжался. В настоящее время он блокируется в задаче Exec, пока окно обозревателя не будет закрыто.

<Target Name="OpenExplorer">
    <Exec Command='explorer.exe "$(DestinationDir)"' IgnoreExitCode="true" />
</Target>

Спасибо! * * 1004

Редактировать: Я надеялся избежать создания пользовательского задания для этого. Возможно, существует какая-то магия командной строки, которую можно поместить в строку для Command?

Ответы [ 5 ]

10 голосов
/ 17 января 2014

Вот простой способ выполнять процессы асинхронно, используя только 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 из вашего обычного сценария следующим образом. Примечание. Мой сценарий ниже используется для сбора покрытия кода для приложения.

<!--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."/>

Вот описание того, что там происходит:

  1. Сначала я запускаю инструмент производительности, чтобы он слушал охват. Я делаю это, используя нашу задачу AsyncExec, потому что обычно блоки инструментов при работе в MSBuild (см. здесь ).
  2. Далее мы запускаем нашу программу, о которой мы хотим получить покрытие.
  3. Затем мы закрываем инструмент покрытия, когда закончим.
8 голосов
/ 05 марта 2010

Вы не можете сделать это с родным 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;
    }
  }

, который вы затем можете запустить:

5 голосов
/ 30 июня 2011
4 голосов
/ 26 ноября 2011

Попробуйте AsyncExec в MSBuild Extension Pack .

3 голосов
/ 18 июля 2011

Команда в Exec помещается в командный файл и выполняется. Таким образом, вы можете использовать ключевое слово «start» в команде так же, как в окне консоли. Это сделает свое дело.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...