2009-08-05 16 views
5

Tengo un archivo de propiedades, digamos my-file.properties. Además de eso, tengo varios archivos de configuración para mi aplicación donde se debe completar cierta información con respecto al contenido del archivo my-file.properties.Simulando el mecanismo de filtro Maven2 usando Ant

my-file.properties:

application.version=1.0 
application.build=42 
user.name=foo 
user.password=bar 

Por lo tanto, en mis archivos de configuración, que se encuentran algunos ${application.version}, ${user.name} que será reemplazado por su valor tomado en el archivo de propiedades ...

Cuando construyo mi aplicación usando Maven2, solo necesito especificar el archivo de propiedades y decir que mis archivos de recursos están filtrados (como en this answer a otro problema). Sin embargo, necesito lograr lo mismo usando solo Ant.

He visto que Ant ofrece un filter task. Sin embargo, me obliga a utilizar el patrón @[email protected] (es decir, @[email protected] en lugar de #{user.name}) en mis archivos de configuración, lo cual no es aceptable en mi caso.

¿Cómo puedo resolver mi problema?

Respuesta

20

Creo que expandproperties es lo que estás buscando. Esto actúa igual que Maven2's resource filters.


ENTRADA

Por ejemplo, si usted tiene src directorio (uno de los muchos archivos):

<link href="${css.files.remote}/css1.css"/> 

src/test.txt


PROCESO

Y en mi fichero de construcción ANT tenemos esto:

<project default="default"> 
    <!-- The remote location of any CSS files --> 
    <property name="css.files.remote" value="/css/theCSSFiles" />  
    ... 
    <target name="ExpandPropertiesTest"> 

     <mkdir dir="./filtered"/> 

     <copy todir="./filtered"> 
     <filterchain> 
      <expandproperties/> 
     </filterchain>  

     <fileset dir="./src" /> 
     </copy> 
    </target> 
</project> 

build.xml


SALIDA

* Cuando se ejecuta el objetivo ExpandPropertiesTest se quiere tenga lo siguiente en su filtrado directorio: *

<link href="/css/theCSSFiles/css1.css"/> 

filtrada/test.txt

+0

¡Gracias! Era realmente lo que estaba buscando ... – romaintaz

+0

@romaintaz ¡Cosa segura! Espero que eso simplifique un poco el archivo de compilación. Sé que hizo lo mío. – leeand00

2

Ant sabe un concepto llamado Filterchains, que es útil aquí. Utilice el filtro ReplaceTokens y especifique begintoken y endtoken como vacíos (normalmente eso es '@'). Eso debería hacer el truco.

+1

Esta solución no parece funcionar, al menos con mis intentos. begintoken y endtoken no pueden estar vacíos. No puedo configurar begintoken a "$ {" ya que se considera un error de sintaxis ... – romaintaz

1

Una forma hooooooorible para hacer este trabajo, inspirado en la solución de Mnementh, es con el siguiente código:

<!-- Read the property file --> 
    <property file="my-file.properties"/> 
    <copy todir="${dist-files}" overwrite="true"> 
     <fileset dir="${src-files}"> 
      <include name="*.properties"/> 
     </fileset> 
     <filterchain> 
      <filterreader classname="org.apache.tools.ant.filters.ReplaceTokens"> 
       <!-- Define the begin and end tokens --> 
       <param type="tokenchar" name="begintoken" value="$"/> 
       <param type="tokenchar" name="endtoken" value="}"/> 
       <!-- Define one token per entry in the my-file.properties. Arggh --> 
       <param type="token" name="{application.version" value="${application.version}"/> 
       <param type="token" name="{user.name" value="${user.name}"/> 
       ... 
      </filterreader> 
     </filterchain> 
    </copy> 

explicaciones:

estoy usando el replaceTokens lector a buscar todas $...} patrón . No puedo buscar los patrones ${...}, ya que el begintoken es un char y no un String. Luego, configuro la lista de tokens comenzando con un {(es decir, veo {user.name en lugar de user.name). Con suerte, no tengo "sólo" alrededor de 20 líneas en my-file.properties, así que necesito para definir "sólo" 20 fichas en mi archivo de Ant ...

¿Hay alguna solución simple y estúpida para resolver este sencillo y ¿problema estúpido?

3

Puede definir un custom FilterReader. Por lo que tiene un par de opciones:

  1. Extender/copiar la clase org.apache.tools.ant.filters.ReplaceTokens y definir una propiedad Mapa que hace referencia a otro archivo de propiedades que contiene todos los reemplazos. Esto todavía es un poco pesado ya que tiene que definir todos los reemplazos.
  2. Extienda/copie la clase org.apache.tools.ant.filters.ReplaceTokens con procesamiento adicional que simplemente sustituye el token coincidente con una versión con la guarnición correcta. Por supuesto, tendrías que tener mucho cuidado al usar este tipo, ya que coincidirá con el token de inicio y final.

Así que en el método read() de replaceTokens, reemplace:

final String replaceWith = (String) hash.get(key.toString()); 

con una llamada a un método getReplacement():

... 
final String replaceWith = getReplacement(key.toString); 
... 

private String getReplacement(String key) { 
    //first check if we have a replacement defined 
    if(has.containsKey(key)) { 
     return (String)hash.get(key); 
    } 

    //now use our built in rule, use a StringBuilder if you want to be tidy 
    return "$" + key + "}"; 
} 

Para utilizar esta, que le asegura su clase está empaquetada y on Ant's path y modifique su filtro:

<filterreader classname="my.custom.filters.ReplaceTokens"> 
    <!-- Define the begin and end tokens --> 
    <param type="tokenchar" name="begintoken" value="$"/> 
    <param type="tokenchar" name="endtoken" value="}"/> 
    <!--Can still define explicit tokens, any not 
    defined explicitly will be replaced by the generic rule --> 
</filterreader>