Создание собственного цикла WHILE в NANT - PullRequest
3 голосов
/ 03 июня 2009

Я старался изо всех сил, чтобы создать собственный цикл while, но тщетно. Кому-нибудь удалось создать собственный цикл while в NANT?

Ответы [ 7 ]

6 голосов
/ 13 апреля 2011

Вы можете создать пользовательское задание:

  <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>
5 голосов
/ 26 сентября 2013

при просмотре списка доступных на данный момент задач для NAnt выглядит, как , тогда как больше не поддерживается (http://nant.sourceforge.net/release/latest/help/tasks/)

Так что я думаю, что самый простой и эффективный способ сделать пользовательский цикл while - это рекурсия.

Так, например, что-то вроде этого:

<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>

С уважением,

Marek

3 голосов
/ 15 ноября 2012

Вот еще один пример простой, но эффективной версии цикла while, реализованного в 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>
1 голос
/ 03 февраля 2012

Есть довольно много способов сделать это. Я написал нечто похожее на Cao, которое приводит к тому, что свойство имеет значение true, поэтому условие может быть настолько сложным, насколько вам нравится, и если оно становится динамическим, значение оценивается в каждом цикле, что удобно при вызове функций, например, проверить файл существует. Я также добавил простой контроль и продолжить контроль. Он также может быть запущен как бесконечный цикл без атрибутов, который может быть полезен, когда вы хотите выйти из множества условий (в этом случае используйте 'if' с break / continue или - в моем случае - я хотел запустить задачу до он исключен, а затем обрабатывается с помощью failonerror или блока trycatch.

Вот немного скрипта Нанта, который показывает два способа отсчета от 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>

А вот пример из реальной жизни, который я использую для ожидания удаления файла блокировки:

<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>

Вот код задачи:

  <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>

0 голосов
/ 08 июня 2017

Вот один из способов написания цикла WHILE в nant без пользовательских задач или элемента script, использующего преимущество failonerror="false" в цикле 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>

Вывод из выполнения цикла WHILE выше выглядит следующим образом. Обратите внимание, что из-за failonerror="false" вызов fail не завершает сценарий:

     [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)

Я основал цикл WHILE выше на том, как я строю цикл FOR, который является несколько упрощенной версией приведенного выше кода:

        <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>

Вывод из цикла FOR выглядит следующим образом:

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

 BUILD SUCCEEDED
0 голосов
/ 04 июня 2009

Я создал пользовательское задание самостоятельно. Но, похоже, в NANT есть некоторые проблемы с использованием вложенных циклов.

В основном я пытаюсь использовать вложенный цикл. Цикл while внутри foreach или foreach внутри другого foreach. Но в обоих случаях цикл выполняет текущую цель и цель, из которой текущая цель вызывается для каждой итерации, а не тело внутри второго цикла.

Привет

Sarathy

0 голосов
/ 03 июня 2009

Без дополнительной информации, здесь есть учебник по созданию пользовательской задачи NAnt здесь .

В статье есть одна приятная вещь: автор предлагает 2 способа отладки вашей пользовательской задачи:

  1. Скопируйте файл сборки (и pdb) в каталог NAnt bin. Откройте свое решение в Visual Studio, которое содержит исходный текст для вашей задачи. Разместите ваши точки останова. Перейдите в свойства проекта и откройте страницу «Отладка». Измените режим отладки на «Программирование» и «Запустите приложение» на путь к исполняемому файлу NAnt (например, C: \ Program Files \ NAnt \ bin \ NAnt.exe). Затем установите рабочий каталог и / или аргументы командной строки, чтобы NAnt подобрал ваш файл сборки. Нажми беги и иди.

  2. Место System.Diagnostics.Debbugger.Break (); в вашем коде перед строкой, которую вы хотите разбить на. Перекомпилируйте проект и скопируйте сборку (и pdb) в каталог NAnt bin. При запуске сценария NAnt вы должны получить всплывающее окно с просьбой выбрать отладчик.

Здесь есть еще один учебник .

В качестве альтернативы, вы можете выразить свою проблему в виде foreach ?

...