2010-03-05 6 views
1

Je vais poster une question que j'ai vu des variantes d'ailleurs, mais où je n'ai pas encore vu la réponse que j'ai trouvée. Je posterai ensuite ma réponse. Afin de modulariser mon script de construction en utilisant des macros, je voudrais mettre à la fois le updatetask et la tâche que je veux exécuter s'il n'est pas à jour, dans la même macro. Comment faire ceci: utiliser la balise de script est ok - si le seul attribut unique transmis est un chemin contenant des barres obliques inverses, et que je dois pouvoir transmettre différentes valeurs à la balise de script sur différentes invocations. Je dois éviter tous les problèmes qui pourraient se produire avec les littéraux de chaîne quand un backslash est impliqué. En utilisant l'attribut unique, je dois contourner le comportement de la propriété antinavire et contourner le modèle de fourmis qui utilise généralement deux cibles pour gérer les décisions de traitement à jour et contourner le traitement javascript des barres obliques inverses dans les chaînes de caractères.ANT. Remplacer les propriétés. Exécution facultative dans la cible unique

Répondre

2

Remarque Je travaille avec Ant 1.7. Avec la portée locale dans Ant 1.8, il y a quelques options supplémentaires pour que l'immuabilité ne soit pas un si grand défi, mais certains de ces autres conseils seront toujours utiles. Tout d'abord, en ce qui concerne la question de l'exécution éventuelle d'une tâche basée sur les résultats de l'uptodate dans une macro - ce qui signifie que vous n'avez pas besoin de 2 cibles. Pour ce faire, utilisez l'étiquette de condition. La balise <ou> l'obligera à exécuter uniquement la deuxième condition si la première condition échoue. La balise <scriptcondition> permet d'utiliser javascript pour exécuter d'autres tâches ant. Voici un exemple (@ balises indiquent les attributs macrodef):

<condition property="whatever" value="false"> 
    <or> 
    <uptodate> 
     <srcfiles dir="@{srcdir}" includes="@{srcincludes}" excludes="@{srcexcludes}"/> 
     <mapper><chainedmapper> 
     <flattenmapper/><!-- use any mappers you need to match source to target files--> 
     <globmapper from="*.jxw" to="@{targetdir}\*W.java"/> 
     </chainedmapper></mapper> 
    </uptodate> 
    <!-- w/ java 1.6 or later, you get a rhino javascript interpreter included w/ java--> 
    <scriptcondition language="javascript" value="true"> 
     self.setValue(true); 
     echo = project.createTask("echo"); 
     myArg1="@{myArg1}"; 
     myArg2="@{myArg2}"; 
     // need to create a reference from a classpath refid 
     myReference = new org.apache.tools.ant.types.Reference(project,"@{my.classpath.id.string}"); 
     // get a handle to the ant java task, which we will use to execute a java program 
     javaTask = project.createTask("java"); 
     javaTask.setFork(true); 
     javaTask.setFailonerror(true); 
     javaTask.setClassname("com.mycompany.mypackage.MySpecialClass"); 
     javaTask.setClasspathRef(myReference); 
     javaTask.createArg().setValue(myArg1); 
     javaTask.createArg().setValue(myArg2); 

     //output the command line to standard out, for reference 
     echo.setMessage(javaTask.getCommandLine()); 
     echo.perform(); 
     javaTask.perform(); 
    </scriptcondition> 
    </or> 
</condition> 

Maintenant, si vous êtes comme moi, vous voudrez peut-être faire un peu de traitement avec les attributs qui sont vos entrées macrodef et produisent des valeurs dérivées qui peuvent être référencées dans votre script macrodef. Si vous traitez simplement une concaténation d'attributs et de chaînes, vous pouvez le faire dans le bloc où vous spécifiez vos attributs en spécifiant un deuxième ensemble d'attributs avec un paramètre par défaut qui contient les étapes de concaténation. Cependant, si vous devez faire quelque chose que vous ne pouvez pas connecter à un attribut par défaut, vous devrez le placer dans une propriété. Les propriétés étant immuables, vous devez prendre des mesures supplémentaires pour attribuer des noms uniques à votre propriété. Le tstamp est pratique pour aider à cela. Généralement, une combinaison des paramètres passés à votre macro sera unique, mais si cette combinaison unique inclut des barres obliques inversées, vous devrez en déduire un identifiant unique secondaire en utilisant la balise tstamp afin de ne pas rencontrer de problème de backslash dans votre javascript. vous voulez utiliser ces propriétés dérivées. Voici comment créer vos propriétés uniques que vous pouvez facilement référencer dans votre script.

<macrodef name="public.macro.example"> 
    <attribute name="srcpath"/> 
    <sequential> 
     <tstamp prefix="@{srcpath}"><format pattern="ddhhmmssSSS" property="time"/></tstamp> 
     <private.macro.example srcpath="@{srcpath}" propertyPrefix="prop${@{srcpath}.time}"/> 
    </sequential> 
</macrodef> 

<macrodef name="private.macro.example"> 
    <attribute name="srcpath"/> 
    <attribute name="prefix"/> 
    <sequential> 
    <pathconvert property="@{prefix}.src"/> 
    <!-- now you can do special things with ${@{prefix}.src}, even in javascript --> 
    <script language="javascript"> 
     self.setValue(true); 
     echo = project.createTask("echo"); 
     myPrefix="@{prefix}"; 
     mySpecialPropertyKey=myPrefix+".src"; 
     //if your special property contains backslashes or other special js characters 
     // you need to use project.getProperty instead of a string literal to get the value 
     mySpecialPropertyVal=project.getProperty(mySpecialPropertyKey); 
     // do something with this derived value in javascript 
     echo.setMessage("my special property = "+mySpecialPropertyVal); 
     echo.perform(); 
    </script> 
    </sequential> 
</macrodef> 

Avant que je suis venu avec la solution ci-dessus, je suis venu avec un style hack de solution pour des raisons impérieuses une propriété de fourmi avec une nouvelle valeur. Bien que vous puissiez trouver cela utile pour remplacer une propriété, parce que je fais un appel direct à une classe de fourmi, il y a un risque que cela ne fonctionne pas de la même manière dans les futures versions de ant. Parce que cela ressemble plus à un hack, mon intention est d'utiliser l'approche 2 macrodef énumérés ci-dessus plutôt que cette approche lorsque cela est possible. Notez que cette variante particulière ne prend pas en charge les caractères barre oblique inverse car les attributs sont directement référencés dans un littéral de chaîne javascript. J'ai d'abord utilisé cette simple variation pour créer mon préfixe unique, ce qui m'a empêché d'utiliser une approche macrodef pour travailler sur l'immutabilité des propriétés. Vous pouvez cependant adapter ce macrodef pour utiliser un 2ème macrodef et un préfixe unique afin d'obtenir le "@ {value}" dans le javascript en utilisant une commande project.getProperty.

<macrodef name="public.canova.setproperty"> 
    <attribute name="name"/> 
    <attribute name="value"/> 
    <sequential> 
    <script language="javascript"> 
     project.setUserProperty("@{name}","@{value}"); 
    </script> 
    <sequential> 
</macrodef> 

À première vue, une partie de cela peut sembler un peu complexe, mais si vous faites votre travail de macrodef droit et construire des macros de style de composants (c.-à ne pas mettre le code spaghetti dans votre macro), vos scripts de fourmis devraient En fait, ils deviennent plus courts, plus faciles à comprendre et plus faciles à entretenir, et les journaux seront plus faciles à suivre. Astuce - n'utilisez javascript qu'en cas de nécessité et lorsque vous l'utilisez, il est préférable de l'utiliser dans une macro afin qu'elle soit encapsulée et cachée de la «logique» principale de votre script ant, aidant ainsi à la nature auto-documentée et lisible de votre «logique» principale. Utilisez des commentaires lorsque les choses ne sont pas évidentes.

+0

Un problème avec cette technique. @ {value} est inséré en tant que chaîne littérale dans le script. Donc, si la valeur contient une barre oblique inverse ou un guillemet double, le résultat n'est pas comme prévu. – gawi

+7

Je sais que c'est un vieux message, mais quant à votre demande d'inclure cette adresse e-mail, s'il vous plaît voir [D'autres personnes peuvent modifier mes messages ?!] (http://stackoverflow.com/faq#editing) (que je suis bien sûr va se passer) et [Comment gérer la réponse là où l'affiche veut créditer le code si elle est utilisée?] (http://meta.stackexchange.com/questions/117084/how-to-handle-answer-where-poster-wants-credit -pour-code-si-utilisé) – Arjan

Questions connexes