¿Por qué estos elementos de salida de MSBuild parecen vacíos cuando no lo están?

Extraña forma de hacer una pregunta, de todos modos ... Básicamente, este es mi primer intento real con MSBuild.

Me las arreglé para crear un Target (RenameJs) que produce una nueva lista de elementos de salida denominada JsMinifyOutput (una versión renombrada de otra lista de entrada).

Luego, en un destino dependiente (CierreCompilar) Estoy tratando de usar la lista de salida generada anteriormente. Tengo una tarea de mensaje como la siguiente, donde puedo ver los valores de la lista de salida impresos en la consola:

    <Message Text="Outputs: %(JsMinifyOutput.FullPath)" />

Pero luego, en el mismo destino dependiente, cuando trato de usar la lista de salida en el real Exec Task, la lista parece estar vacía. La siguiente tarea:

<Exec Command="$(ClosureCompilerCmd) --js %(JsMinify.FullPath) --js_output_file %(JsMinifyOutput.FullPath)" />

aparece en la consola como solo:

java -jar Some\Path\To\SomeInputFile.debug.js --js_output_file

mientras que esperaría algo como:

java -jar Some\Path\To\SomeInputFile.js --js_output_file Some\Path\To\SomeFileRenamed.js

Si intento con esta sencilla tarea Exec, muestra correctamente todos los nombres de archivo:

<Exec Command="echo %(JsMinifyOutput.FullPath)" />

Lo que estoy tratando de lograr aquí es lo siguiente: a partir de una lista de ItemGroup de entrada, crear otra lista de ItemGroup (de salida) mediante alguna transformación sobre la anterior (por ejemplo, cambiar el nombre, reemplazar el texto, ...). Luego, teniendo estas dos listas de ItemGroup, recorrelas en paralelo por así decirlo, y realizar una tarea de Exec sobre ellos. En pseudolenguaje, algo como:

 for(i from 0 to inList.length)
 {
   Exec Command="Path\To\Some\Command --in inList[i] --out outList[i]
 } 

¿Estoy haciendo algo completamente tonto aquí? PD: Esto es con Build Engine Versión 4.0, .NET Framework Versión 4.0

preguntado el 08 de noviembre de 11 a las 12:11

podría depender de lo que está en la parte 'omitida': si hace referencia a otra lista con un signo%, podría arruinar las cosas -

sí, hace referencia a otra lista con '%', procedente de un ItemGroup. ¿Eso causa problemas? Por cierto, edité la pregunta para eliminar la parte omitida. -

2 Respuestas

Uhm, parece que Exec Task no puede iterar sobre dos paralelo ItemGroups al mismo tiempo. ... Al menos eso es lo que responde un gurú de MSBuild aquí:

El problema es que está agrupando 2 elementos a la vez.

No estoy totalmente seguro de si lo que estoy tratando de hacer aquí es "agrupar en 2 elementos a la vez".

EDITAR

Habiendo aclarado cuál es la razón real por la que la tarea no funciona, este es mi enfoque (lo que creo que es) una solución limpia:

  1. Agregar una nueva metadatos a la entrada existente ItemGroup. Esos metadatos is la ruta de salida calculada y toma el lugar del anterior ItemGroup de salida. Dentro de los metadatos encontrará la transformación de la ruta de archivo (cambiar el nombre, reemplazar, ...) lograda de alguna manera (a través de Tarea en línea, Función de propiedad, Transformar, Tu dilo).
  2. Haga referencia a los nuevos metadatos donde se usó el ItemGroup de salida anterior, por ejemplo, dentro de Exec Command atributo, o dentro del Target Outputs atributo.

A modo de ejemplo:

<Target Name="JsRename"> <!-- This adds the metadata -->
  <ItemGroup>
    <JsMinify>
      <OutputPath>[do something over %(FullPath)</OutputPath>
    </JsMinify>
  </ItemGroup>
</Target>
<Target Name="ClosureCompile" DependsOnTargets="JsRename"> <!-- Here is the actual task -->
  <Exec Command="$(ClosureCompilerCmd) --js %(JsMinify.FullPath) --js_output_file %(JsMinify.OutputPath)" />
</Target>

contestado el 23 de mayo de 17 a las 15:05

eso definitivamente no es solo con Exec, sino con todas las tareas. - stijn

Desde mi experiencia (limitada) con msbuild, parece que no puede usar dos listas como esa. Simplemente ponga lo mismo en la tarea Mensaje y verá lo que está haciendo.

Sin embargo, puede usar una lista con metadatos, lo que solo requiere que genere el producto cruzado manualmente a partir de las otras dos listas:

<ItemGroup>
  <JsMinify Include="a"/>
  <JsMinify Include="b"/>
  <JsMinifyOutput Include="d"/>
  <JsMinifyOutput Include="e"/>
</ItemGroup>

<Target Name="CrossProduct">
  <ItemGroup>
    <InPath Include="@(JsMinify->'%(Identity)')">
      <OutPath>%(JsMinifyOutput.Identity)</OutPath>
    </InPath>
  </ItemGroup>
</Target>

<Target Name="Show" DependsOnTargets="CrossProduct">
  <Message Text="%(InPath.Identity) and %(InPath.OutPath)"/>
</Target>

ejecutar esto dará como resultado

  a and d
  b and d
  a and e
  b and e

Noticias Hay varias formas de realizar el procesamiento por lotes; aquí hay un poco diferente en el que también tienes que agregar metadatos pero de otra manera; de hecho, siguiendo su pseudocódigo de bucle, el JsGroup que utilicé a continuación corresponde al contador de bucle. Si bien esta muestra parece hacer lo que buscas, desafortunadamente no conozco una forma automática de generar los números, por lo que no es realmente una solución, pero la publicaré de todos modos, ya que es lo suficientemente interesante.

<ItemGroup>
  <JsMinify Include="a">
    <JsGroup>1</JsGroup>
  </JsMinify>
  <JsMinify Include="b">
    <JsGroup>2</JsGroup>
  </JsMinify>

  <JsMinifyOutput Include="d">
    <JsGroup>1</JsGroup>
  </JsMinifyOutput>
  <JsMinifyOutput Include="e">
    <JsGroup>2</JsGroup>
  </JsMinifyOutput>
</ItemGroup>

<Message Text="%(JsGroup): @(JsMinify) and @(JsMinifyOutput)"/>

Salidas

a and d
b and e

Miré más allá y, dado que está utilizando msbuild 4, se abre un nuevo mundo de posibilidades. Usando el mismo ItemGroup y superior, aquí hay una tarea en línea que llama a su ciclo en código real:

<UsingTask TaskName="LoopBoth" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
  <ParameterGroup>
    <JsMinify ParameterType="System.String[]" Required="true" />
    <JsMinifyOutput ParameterType="System.String[]" Required="true" />
  </ParameterGroup>
  <Task>
    <Code Type="Fragment" Language="cs">
      <![CDATA[
          for( int i = 0 ; i < JsMinify.Length ; ++i )
          {
            Log.LogMessage( JsMinify[ i ] + " and " + JsMinifyOutput[ i ] );
            System.Diagnostics.Process.Start( "java",
              "-jar " + JsMinify[ i ] + " --js_output_file " + JsMinifyOutput[ i ] );
          }
      ]]>
    </Code>
  </Task>
</UsingTask>

<Target Name="DoIt">
  <LoopBoth JsMinify="@(JsMinify)" JsMinifyOutput="@(JsMinifyOutput)"/>
</Target>

Por supuesto, podría extender esto y pasar solo JsMinify y hacer la transformación dentro de la tarea.

respondido 09 nov., 11:00

forma interesante de utilizar ItemGroups. Pero en realidad lo hago no quiere el producto cruzado. En cambio, me gustaría procesar artículos en paralelo, por ejemplo, ejecute la tarea para cada par de elementos en JsMinify y JsMinifyOutput. - superjos

¿puedes elaborar? Con paralelo, ¿te refieres a "al mismo tiempo"? En ese caso, Exec no hace eso afaik, pero puede recurrir a llamar a la tarea msbuild en varios archivos de proyecto al mismo tiempo, ya que la tarea msbuild puede ejecutarse en paralelo. Pero incluso entonces, creo que necesitaría construir este producto cruzado en alguna parte. - stijn

por favor, eche un vistazo a mi pregunta editada. Y por cierto, gracias por tu tiempo. - superjos

También he llegado a una solución y la publicaré aquí también como referencia. Sí, jugué con tareas en línea v4.0, así como con funciones de propiedad y metadatos de ItemGroup. no estrictamente tiene o necesita un índice, o un bucle, y como notó, eso es solo un pseudocódigo. No estoy seguro ahora cuál es la respuesta :) - superjos

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.