2009-06-03 8 views
3

J'ai fait de mon mieux pour créer une boucle while personnalisée mais terminée en vain. Est-ce que quelqu'un a réussi à créer une boucle personnalisée dans NANT?Création d'une boucle WHILE personnalisée dans NANT

+0

Pouvez-vous décrire le problème que vous essayez de résoudre avec la boucle while? Il y a peut-être un autre moyen. –

Répondre

0

Sans informations supplémentaires, il existe un tutoriel sur la création d'une tâche NAnt personnalisée here.

Une bonne chose à propos de l'article est l'auteur suggère 2 moyens de débogage votre tâche personnalisée:

  1. Copiez l'ensemble (et pdb) fichier dans le répertoire bin NAnt. Ouvrez votre solution dans Visual Studio qui contient la source pour votre tâche. Placez vos points d'arrêt. Accédez aux propriétés du projet et ouvrez la page Débogage. Modifiez le mode de débogage à programme et l'application de démarrage au chemin d'accès à l'exécutable NAnt (par exemple C: \ Program Files \ NAnt \ bin \ NAnt.exe). Ensuite, définissez le répertoire de travail et/ou les arguments de ligne de commande afin que NAnt récupère votre fichier de construction. Cliquez sur courir et vous partez.

  2. Placez System.Diagnostics.Debbugger.Break(); dans votre code avant la ligne que vous voulez rompre. Re-compilez le projet et copiez l'assembly (et pdb) dans le répertoire bin NAnt. Lorsque vous exécutez votre script NAnt, vous devriez obtenir une fenêtre contextuelle vous demandant de choisir un débogueur.

Il existe un autre tutoriel here.

Alternativement, pouvez-vous exprimer votre problème en termes de foreach?

0

J'ai créé la tâche personnalisée par moi-même. Mais il semble qu'il y ait quelques problèmes dans l'utilisation des boucles imbriquées dans NANT.

Fondamentalement, j'essaie d'utiliser la boucle imbriquée. Une boucle while dans un foreach ou un foreach dans un autre foreach. Mais dans les deux cas, la boucle exécute la cible actuelle & cible à partir de laquelle la cible actuelle est appelée pour chaque itération au lieu du corps à l'intérieur de la deuxième boucle.

Cordialement

Sarathy

+0

Souhaitez-vous publier un exemple dépouillé et minimaliste de tâches de code et NAnt pouvant démontrer le problème? – JeffH

6

Vous pouvez créer une tâche personnalisée:

<target name="sample"> 
    <property name="foo.value" value="0"/> 
    <while property="foo.value" equals="0"> 
     <do> 
     <echo message="${foo.value}"/> 
     <property name="foo.value" value="${int::parse(foo.value) + 1}"/> 
     </do> 
    </while> 
    </target> 

    <script language="C#" prefix="directory"> 
    <code> 
     <![CDATA[ 
[TaskName("while")] 
public class WhileTask : TaskContainer 
{ 
    private TaskContainer _doStuff; 
    private string _propertyName; 
    private string _equals; 
    private string _notEquals; 

    [BuildElement("do")] 
    public TaskContainer StuffToDo 
    { 
     get 
     { 
      return this._doStuff; 
     } 
     set 
     { 
      this._doStuff = value; 
     } 
    } 

    [TaskAttribute("property")] 
    public string PropertyName 
    { 
     get 
     { 
      return this._propertyName; 
     } 
     set 
     { 
      this._propertyName = value; 
     } 
    } 

    [TaskAttribute("equals")] 
    public string Equals 
    { 
     get 
     { 
      return this._equals; 
     } 
     set 
     { 
      this._equals = value; 
     } 
    } 

    [TaskAttribute("notequals")] 
    public string NotEquals 
    { 
     get 
     { 
      return this._notEquals; 
     } 
     set 
     { 
      this._notEquals = value; 
     } 
    } 

    protected override void ExecuteTask() 
    { 
     while (this.IsTrue()) 
     { 
      this._doStuff.Execute(); 
     } 
    } 

    private bool IsTrue() 
    { 
     if (!string.IsNullOrEmpty(this.Equals)) 
     { 
      return this.Properties[this.PropertyName] == this.Equals; 
     } 
     return this.Properties[this.PropertyName] != this.NotEquals; 
    } 
} 
    ]]> 
    </code> 
    </script> 
1

Il y a assez peu de moyens, vous pouvez le faire. J'ai écrit quelque chose de similaire à Cao qui déclenche une propriété étant vrai, donc la condition peut être aussi complexe que vous voulez et si elle est rendue dynamique, la valeur est évaluée chaque boucle qui est pratique lorsque vous appelez des fonctions, par exemple. pour vérifier un fichier existe. J'ai également ajouté des contrôles simples de rupture et de continuation. Il peut également être exécuté comme une boucle infinie sans attribut qui peut être utile soit lorsque vous voulez quitter beaucoup de conditions (dans ce cas utilisez 'si' avec break/continue ou - dans mon cas - je voulais exécuter une tâche jusqu'à il a été exceptionnellement géré et géré avec failonerror ou un bloc trycatch.

est ici un peu de scénario Nant qui montre deux façons de compte à rebours de 10:

<property name="greaterthanzero" value="${int::parse(count) > 0}" dynamic="true"/> 

<property name="count" value="10" /> 
<while propertytrue="greaterthanzero" > 
    <echo>CountDown = ${count}</echo> 
    <property name="count" value="${int::parse(count) - 1}" /> 
</while> 

<property name="count" value="10" /> 
<while> 
    <if test="${int::parse(count) > 0}" > 
    <echo>CountDown = ${count}</echo> 
    <property name="count" value="${int::parse(count) - 1}" /> 
    <continue/> 
    </if> 
    <break/> 
</while> 

Et voici un exemple du monde réel que j'utilise pour attendre jusqu'à ce qu'un lockfile est supprimé:

<property name="count" value="0" /> 
<property name="lockfileexists" value="${file::exists(lockfile)}" dynamic="true"/> 
<while propertytrue="lockfileexists" > 
    <sleep seconds="1" /> 
    <property name="count" value="${int::parse(count) + 1}" /> 
    <if test="${count == '15'}" > 
    <echo>Timed out after 15 seconds</echo> 
    <break/> 
    </if> 
</while> 

Voici le code de la tâche:

<script language="C#" prefix="loops"> 
<code> 
    <![CDATA[ 

    public class LoopBreakException : Exception {} 
    public class LoopContinueException : Exception {} 

    [TaskName("break")] 
    public class BreakTask : Task 
    { 
     protected override void ExecuteTask() 
     { 
      throw new LoopBreakException(); 
     } 
    } 

    [TaskName("continue")] 
    public class ContinueTask : Task 
    { 
     protected override void ExecuteTask() 
     { 
      throw new LoopContinueException(); 
     } 
    } 

    [TaskName("while")] 
    public class WhileTask : TaskContainer 
    { 
     [TaskAttribute("propertytrue")] 
     public string PropertyName { get; set; } 

     protected bool CheckCondition() 
     { 
      if (!string.IsNullOrEmpty(PropertyName)) 
      { 
       try 
       { 
        return bool.Parse(Properties[PropertyName]); 
       } 
       catch (Exception ex) 
       { 
        throw new BuildException(string.Format("While Property '{0}' not found", PropertyName), Location); 
       } 
      } 
      //for infinite loops 
      return true; 
     } 

     protected override void ExecuteTask() 
     { 
      while (CheckCondition()) 
      { 
       try 
       { 
        ExecuteChildTasks(); 
       } 
       catch (LoopContinueException) 
       { 
        continue; 
       } 
       catch (LoopBreakException) 
       { 
        break; 
       } 
      } 
     } 
    } 
]]> 
</code> 

3

Voici un autre exemple d'une version simple mais efficace de la boucle while implémentée dans NAnt.

<?xml version="1.0"?> 
<project name="whiletask" xmlns="http://tempuri.org/nant-donotuse.xsd"> 

    <script language="C#" prefix="loop"> 
    <code> 
     <![CDATA[ 

    /// <summary> 
    /// A while loop task. Will continuelly execute the task while the <c>test</c> is <c>empty</c> 
    /// or evalutes to <c>true</c>. 
    /// </summary> 
    [TaskName("while")] 
    public class WhileTask : TaskContainer 
    { 
     private string _test; 
     private TaskContainer _childTasks; 

     /// <summary> 
     /// The expression to test each iteration. If empty, then always evalutes to true (i.e. infinite loop.) 
     /// </summary> 
     [TaskAttribute("test", ExpandProperties = false)] 
     public string Test 
     { 
      get { return _test; } 
      set { _test = NAnt.Core.Util.StringUtils.ConvertEmptyToNull(value); } 
     } 

     /// <summary> 
     /// Superficial to ensure the XML schema is rendered correctly for this task. It will get executed 
     /// if tasks exist within it. 
     /// </summary> 
     [BuildElement("do")] 
     public TaskContainer ChildTasks 
     { 
      get { return _childTasks; } 
      set { _childTasks = value; } 
     } 

     /// <summary> 
     /// Executes the while loop while the <c>test</c> evalutes to true or <c>test</c> is empty. 
     /// </summary> 
     protected override void ExecuteTask() 
     { 
      while (this.Test == null 
       || bool.Parse(Project.ExpandProperties(this.Test, this.Location))) 
      { 
       if (this._childTasks != null) 
       { 
        this._childTasks.Execute(); 
       } 
       else 
       { 
        base.ExecuteTask(); 
       } 
      } 
     } 
    } 

      ]]> 
    </code> 
    </script> 

    <property name="i" value="0" /> 
    <while test="${int::parse(i) &lt;= 10}"> 
    <echo message="${i}" /> 
    <property name="i" value="${int::parse(i)+1}" /> 
    </while> 

</project> 
5

regardant la liste des tâches actuellement disponibles pour NAnt, il ressemble à tout est pas plus pris en charge (http://nant.sourceforge.net/release/latest/help/tasks/)

Je pense que la façon la plus simple et la plus efficace comment faire une coutume en la boucle est récursive.

Ainsi, par exemple, quelque chose comme ceci:

<property name="count" value="120" /> 

<target name="wait">   
    <if test="${int::parse(count) > 0}" > 
     <property name="count" value="${int::parse(count) - 1}" /> 

     <call target="wait"/> 
    </if> 
</target> 

Cordialement,

Marek

0

Voici une façon d'écrire une boucle while Nant, sans tâches personnalisées ou élément script, Profitant de failonerror="false" sur une boucle foreach.

<property name="n" value="10000" /><!-- this would be inefficient if "n" is very large --> 
    <property name="i" value="0" /> 
    <foreach item="String" in="${string::pad-right(' ', int::parse(n), ',')}" delim="," property="val" failonerror="false" > 
     <if test="${int::parse(i) &gt; 3}"><!-- put our exit condition here --> 
      <fail message="condition met, exit loop early" /> 
     </if> 
     <echo message="i: ${i}" /> 
     <property name="i" value="${int::parse(i) + 1}" /> 
    </foreach> 

La sortie de l'exécution de la boucle WHILE ci-dessus est la suivante. Notez que, en raison de la failonerror="false" l'appel fail ne se termine pas le script:

 [echo] i: 0 
    [echo] i: 1 
    [echo] i: 2 
    [echo] i: 3 
    [foreach] myscript.nant(24,18): 
    [foreach] condition met, exit loop early 

    BUILD SUCCEEDED - 1 non-fatal error(s), 0 warning(s) 

Je basé la boucle while ci-dessus sur la façon dont je construis une boucle FOR, qui est une version légèrement simplifiée du code ci-dessus:

 <property name="n" value="5" /> 
     <property name="i" value="0" /> 
     <foreach item="String" in="${string::pad-right(' ', int::parse(n), ',')}" delim="," property="val" > 
      <echo message="i: ${i}" /> 
      <property name="i" value="${int::parse(i) + 1}" /> <!-- increment "i" --> 
     </foreach> 

la sortie de la boucle FOR ressemble à ceci:

 [echo] i: 0 
    [echo] i: 1 
    [echo] i: 2 
    [echo] i: 3 
    [echo] i: 4 

BUILD SUCCEEDED 
+0

J'ai aussi inclus le code pour une boucle FOR, car quelqu'un qui consulte cette question pourrait chercher une telle chose. – Boinst

Questions connexes