You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by bo...@apache.org on 2003/05/13 16:37:04 UTC

cvs commit: ant/src/main/org/apache/tools/ant/taskdefs/optional/net RExecTask.java TelnetTask.java

bodewig     2003/05/13 07:37:04

  Modified:    .        WHATSNEW build.xml
               docs/manual install.html optionaltasklist.html
               src/main/org/apache/tools/ant/taskdefs defaults.properties
               src/main/org/apache/tools/ant/taskdefs/optional/net
                        TelnetTask.java
  Added:       docs/manual/OptionalTasks rexec.html
               src/main/org/apache/tools/ant/taskdefs/optional/net
                        RExecTask.java
  Log:
  Add <rexec> to accompany <telnet> and/or <sshexec>.
  
  PR: 19541
  Submitted by:	Fran�ois Rey <francois dot rey at capco dot com>
  
  Revision  Changes    Path
  1.416     +3 -0      ant/WHATSNEW
  
  Index: WHATSNEW
  ===================================================================
  RCS file: /home/cvs/ant/WHATSNEW,v
  retrieving revision 1.415
  retrieving revision 1.416
  diff -u -r1.415 -r1.416
  --- WHATSNEW	13 May 2003 07:22:02 -0000	1.415
  +++ WHATSNEW	13 May 2003 14:36:56 -0000	1.416
  @@ -316,6 +316,9 @@
   * <rpm> will detect the rpmbuild executable of RedHat 8.0 and newer
     and use that if it is on your PATH.  Bugzilla Report 14650.
   
  +* A new task <rexec> has been added that requires commons-net to work.
  +  Bugzilla Report 19541.
  +
   Changes from Ant 1.5.2 to Ant 1.5.3
   ===================================
   
  
  
  
  1.376     +1 -0      ant/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/ant/build.xml,v
  retrieving revision 1.375
  retrieving revision 1.376
  diff -u -r1.375 -r1.376
  --- build.xml	6 May 2003 15:19:16 -0000	1.375
  +++ build.xml	13 May 2003 14:36:59 -0000	1.376
  @@ -234,6 +234,7 @@
     <selector id="needs.commons.net">
       <or>
         <filename name="${optional.package}/net/FTP*"/>
  +      <filename name="${optional.package}/net/RExec*"/>
         <filename name="${optional.package}/net/TelnetTask*"/>
       </or>
     </selector>
  
  
  
  1.52      +1 -1      ant/docs/manual/install.html
  
  Index: install.html
  ===================================================================
  RCS file: /home/cvs/ant/docs/manual/install.html,v
  retrieving revision 1.51
  retrieving revision 1.52
  diff -u -r1.51 -r1.52
  --- install.html	23 Apr 2003 15:57:43 -0000	1.51
  +++ install.html	13 May 2003 14:37:00 -0000	1.52
  @@ -378,7 +378,7 @@
     </tr>
     <tr>
       <td>commons-net.jar</td>
  -    <td>ftp and telnet tasks</td>
  +    <td>ftp, rexec and telnet tasks</td>
       <td><a href="http://jakarta.apache.org/commons/net/index.html"
              target="_top">http://jakarta.apache.org/commons/net/index.html</a></td>
     </tr>
  
  
  
  1.38      +1 -0      ant/docs/manual/optionaltasklist.html
  
  Index: optionaltasklist.html
  ===================================================================
  RCS file: /home/cvs/ant/docs/manual/optionaltasklist.html,v
  retrieving revision 1.37
  retrieving revision 1.38
  diff -u -r1.37 -r1.38
  --- optionaltasklist.html	16 Apr 2003 12:44:44 -0000	1.37
  +++ optionaltasklist.html	13 May 2003 14:37:00 -0000	1.38
  @@ -53,6 +53,7 @@
   <a href="OptionalTasks/pvcstask.html">Pvcs</a><br>
   <a href="OptionalTasks/renameextensions.html"><i>RenameExtensions</i></a><br>
   <a href="OptionalTasks/replaceregexp.html">ReplaceRegExp</a><br>
  +<a href="OptionalTasks/rexec.html">RExec</a><br>
   <a href="OptionalTasks/rpm.html">Rpm</a><br>
   <a href="OptionalTasks/serverdeploy.html">ServerDeploy</a><br>
   <a href="OptionalTasks/setproxy.html">Setproxy</a><br>
  
  
  
  1.1                  ant/docs/manual/OptionalTasks/rexec.html
  
  Index: rexec.html
  ===================================================================
  <html>
  
  <head>
  <meta http-equiv="Content-Language" content="en-us">
  <title>RExec Task</title>
  </head>
  
  <body>
  
  <h2><a name="rexec">RExec</a></h2>
  <h3>Description</h3>
  Task to automate a remote rexec session. Just like the Telnet task,
  it uses nested <tt>&lt;read&gt;</tt> to indicate strings to wait for, and
  <tt>&lt;write&gt;</tt> tags to specify text to send to the remote process.
  
  <p><b>Note:</b> This task depends on external libraries not included in the Ant distribution.
  See <a href="../install.html#librarydependencies">Library Dependencies</a> for more information.</p>
  
  <h3>Parameters</h3>
  <table border="1" cellpadding="2" cellspacing="0">
    <tr>
      <th>Attribute</th>
      <th>Values</th>
      <th>Required</th>
    </tr>
    <tr>
       <td>userid</td>
       <td>the login id to use on the remote server.</td>
       <td>Yes</td>
    </tr>
    <tr>
       <td>password</td>
       <td>the login password to use on the remote server.</td>
       <td>Yes</td>
    </tr>
    <tr>
       <td>server</td>
       <td>the address of the remote rexec server.</td>
       <td>Yes</td>
    </tr>
    <tr>
       <td>command</td>
       <td>the command to execute on the remote server.</td>
       <td>Yes</td>
    </tr>
    <tr>
       <td>port</td>
       <td>the port number of the remote rexec server. Defaults to port 512 in BSD Unix systems.</td>
       <td>No</td>
    </tr>
    <tr>
       <td>timeout</td>
       <td>set a default timeout to wait for a response. Specified in seconds. Default is no timeout.</td>
       <td>No</td>
    </tr>
  </table>
  <h3><a name="nested">Nested Elements</a></h3>
  The input to send to the server, and responses to wait for, are
  described as nested elements.  
  
  <h4>read</h4>
  
  <p>declare (as a text child of this element) a string to wait for.
  The element supports the timeout attribute, which overrides any
  timeout specified for the task as a whole. It also has a <tt>string</tt>
  attribute, which is an alternative to specifying the string as 
  a text element.
  </p>
  <i>It is not necessary to declare a closing &lt;read&gt; element like for the Telnet task. The connection is not broken until the command has completed and
  the input stream (output of the command) is terminated.
  </i>
  <h4>write</h4>
  
  <p>describes the text to send to the server. The <tt>echo</tt> boolean
  attribute controls whether the string is echoed to the local log; 
  this is "true" by default
  </p>
  <h3>Example</h3>
  A simple example of connecting to a server and running a command.
  
  <blockquote><pre>
  &lt;rexec userid=&quot;bob&quot; password=&quot;badpass&quot; server=&quot;localhost&quot; command=&quot;ls&quot;/&gt;
  </pre></blockquote>
  
  The task can be used with other ports as well:
  <blockquote><pre>
  &lt;rexec port=&quot;80&quot; userid=&quot;bob&quot; password=&quot;badpass&quot; server=&quot;localhost&quot; command=&quot;ls&quot;/&gt;
  </pre></blockquote>
  
  <hr>
  <p align="center">Copyright &copy; 2003 Apache Software Foundation. All rights
  Reserved.</p>
  
  </body>
  </html>
  
  
  
  
  1.147     +1 -0      ant/src/main/org/apache/tools/ant/taskdefs/defaults.properties
  
  Index: defaults.properties
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/defaults.properties,v
  retrieving revision 1.146
  retrieving revision 1.147
  diff -u -r1.146 -r1.147
  --- defaults.properties	9 May 2003 12:10:36 -0000	1.146
  +++ defaults.properties	13 May 2003 14:37:03 -0000	1.147
  @@ -189,6 +189,7 @@
   scp=org.apache.tools.ant.taskdefs.optional.ssh.Scp
   sshexec=org.apache.tools.ant.taskdefs.optional.ssh.SSHExec
   jsharpc=org.apache.tools.ant.taskdefs.optional.dotnet.JSharp
  +rexec=org.apache.tools.ant.taskdefs.optional.net.RExecTask
   
   # deprecated ant tasks (kept for back compatibility)
   starteam=org.apache.tools.ant.taskdefs.optional.scm.AntStarTeamCheckOut
  
  
  
  1.20      +4 -4      ant/src/main/org/apache/tools/ant/taskdefs/optional/net/TelnetTask.java
  
  Index: TelnetTask.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/optional/net/TelnetTask.java,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- TelnetTask.java	24 Feb 2003 08:25:19 -0000	1.19
  +++ TelnetTask.java	13 May 2003 14:37:04 -0000	1.20
  @@ -330,7 +330,7 @@
               try {
                   StringBuffer sb = new StringBuffer();
                   if (timeout == null || timeout.intValue() == 0) {
  -                    while (sb.toString().indexOf(s) == -1){
  +                    while (sb.toString().indexOf(s) == -1) {
                           sb.append((char) is.read());
                       }
                   } else {
  @@ -338,12 +338,12 @@
                       endTime.add(Calendar.SECOND, timeout.intValue());
                       while (sb.toString().indexOf(s) == -1) {
                           while (Calendar.getInstance().before(endTime) &&
  -                        is.available() == 0) {
  +                               is.available() == 0) {
                               Thread.sleep(250);
                           }
                           if (is.available() == 0) {
                               throw new BuildException(
  -                                "Response timed-out waiting for \""+s+'\"',
  +                                "Response timed-out waiting for \"" + s + '\"',
                                   getLocation());
                           }
                           sb.append((char) is.read());
  
  
  
  1.1                  ant/src/main/org/apache/tools/ant/taskdefs/optional/net/RExecTask.java
  
  Index: RExecTask.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2003 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "Ant" and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.tools.ant.taskdefs.optional.net;
  
  import org.apache.commons.net.bsd.RExecClient;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.util.Calendar;
  import java.util.Enumeration;
  import java.util.Vector;
  import org.apache.tools.ant.BuildException;
  import org.apache.tools.ant.Project;
  import org.apache.tools.ant.Task;
  
  /**
   * Automates the rexec protocol.
   *
   * @since Ant 1.6
   */
  
  public class RExecTask extends Task {
      /**
       *  The userid to login with, if automated login is used
       */
      private String userid  = null;
  
      /**
       *  The password to login with, if automated login is used
       */
      private String password = null;
  
      /**
       *  The command to execute
       */
      private String command = null;
  
      /**
       *  The server to connect to. 
       */
      private String server  = null;
  
      /**
       *  The tcp port to connect to. 
       */
      private int port = RExecClient.DEFAULT_PORT;
  
      /**
       *  The Object which handles the rexec session.
       */
      private AntRExecClient rexec = null;
  
      /**
       *  The list of read/write commands for this session
       */
      private Vector rexecTasks = new Vector();
  
      /**
       *  If true, adds a CR to beginning of login script
       */
      private boolean addCarriageReturn = false;
  
      /**
       *  Default time allowed for waiting for a valid response
       *  for all child reads.  A value of 0 means no limit.
       */
      private Integer defaultTimeout = null;
  
      /**  
       *  This class is the parent of the Read and Write tasks.
       *  It handles the common attributes for both.
       */
      public class RExecSubTask {
          protected String taskString = "";
          public void execute(AntRExecClient rexec) 
                  throws BuildException {
              throw new BuildException("Shouldn't be able instantiate a SubTask directly");
          }
  
          /**
           *  the message as nested text
           */
          public void addText(String s) {
              setString(getProject().replaceProperties(s));
          }
  
          /**
           * the message as an attribute
           */
          public void setString(String s) {
             taskString += s;
          }
      }
  
      /**
       *  Sends text to the connected server
       */
      public class RExecWrite extends RExecSubTask {
          private boolean echoString = true;
          public void execute(AntRExecClient rexec) 
                 throws BuildException {
             rexec.sendString(taskString, echoString);
          }
  
          /**
           * Whether or not the message should be echoed to the log.
           * Defaults to <code>true</code>.
           */
          public void setEcho(boolean b) {
             echoString = b;
          }
      }
  
      /**
       *  Reads the output from the connected server
       *  until the required string is found or we time out.
       */
      public class RExecRead extends RExecSubTask {
          private Integer timeout = null;
          public void execute(AntRExecClient rexec) 
                 throws BuildException {
              rexec.waitForString(taskString, timeout);
          }
          /**
           *  a timeout value that overrides any task wide timeout.
           */
          public void setTimeout(Integer i) {
             this.timeout = i;
          }
  
          /**
           * Sets the default timeout if none has been set already
           * @ant.attribute ignore="true"
           */
          public void setDefaultTimeout(Integer defaultTimeout) {
             if (timeout == null) {
                timeout = defaultTimeout;
             }
          }
      }
  
      /**
       *  This class handles the abstraction of the rexec protocol.
       *  Currently it is a wrapper around <a
       *  href="http://jakarta.apache.org/commons/net/index.html">Jakarta
       *  Commons Net</a>.
       */
      public class AntRExecClient extends RExecClient {
          /**
           * Read from the rexec session until the string we are 
           * waiting for is found 
           * @param s The string to wait on 
           */
          public void waitForString(String s) {
              waitForString(s, null);
          }
  
          /**
           * Read from the rexec session until the string we are 
           * waiting for is found or the timeout has been reached
           * @param s The string to wait on
           * @param timeout The maximum number of seconds to wait
           */
          public void waitForString(String s, Integer timeout) {
              InputStream is = this.getInputStream();
              try {
                  StringBuffer sb = new StringBuffer();
                  if (timeout == null || timeout.intValue() == 0) {
                      while (sb.toString().indexOf(s) == -1) {
                          sb.append((char) is.read());
                      }
                  } else {
                      Calendar endTime = Calendar.getInstance();
                      endTime.add(Calendar.SECOND, timeout.intValue());
                      while (sb.toString().indexOf(s) == -1) {
                          while (Calendar.getInstance().before(endTime) &&
                                 is.available() == 0) {
                              Thread.sleep(250);
                          }
                          if (is.available() == 0) {
                              throw new BuildException(
                                  "Response timed-out waiting for \"" + s + '\"',
                                  getLocation());
                          }
                          sb.append((char) is.read());
                      }
                  }
                  log(sb.toString(), Project.MSG_INFO);
              } catch (BuildException be) {
                  throw be;
              } catch (Exception e) {
                  throw new BuildException(e, getLocation());
              }
          }
  
          /**
           * Write this string to the rexec session.
           * @param echoString  Logs string sent
           */
          public void sendString(String s, boolean echoString) {
              OutputStream os = this.getOutputStream();
              try {
                  os.write((s + "\n").getBytes());
                  if (echoString) {
                      log(s, Project.MSG_INFO);
                  }
                  os.flush();
              } catch (Exception e) {
                  throw new BuildException(e, getLocation());
              }
          }
          /**
           * Read from the rexec session until the EOF is found or
           * the timeout has been reached
           * @param timeout The maximum number of seconds to wait
           */
          public void waitForEOF(Integer timeout) {
              InputStream is = this.getInputStream();
              try {
                  StringBuffer sb = new StringBuffer();
                  if (timeout == null || timeout.intValue() == 0) {
  	            int read;
                      while ((read = is.read()) != -1) {
                          char c = (char) read;
                          sb.append(c);
                          if (c == '\n') {
  	                    log(sb.toString(), Project.MSG_INFO);
  	                    sb.delete(0, sb.length());
                          }
                      }
                  } else {
                      Calendar endTime = Calendar.getInstance();
                      endTime.add(Calendar.SECOND, timeout.intValue());
  	            int read = 0;
                      while (read != -1) {
                          while (Calendar.getInstance().before(endTime) && is.available() == 0) {
                              Thread.sleep(250);
                          }
                          if (is.available() == 0) {
  	                    log(sb.toString(), Project.MSG_INFO);
                              throw new BuildException(
                                                       "Response timed-out waiting for EOF",
                                                       getLocation());
                          }
                          read =  is.read();
                          if (read != -1) {
  	                    char c = (char) read;
  	                    sb.append(c);
  	                    if (c == '\n') {
                                  log(sb.toString(), Project.MSG_INFO);
                                  sb.delete(0, sb.length());
  	                    }
                          }
                      }
                  }
                  if (sb.length() > 0) {
  	            log(sb.toString(), Project.MSG_INFO);
                  }
              } catch (BuildException be) {
                  throw be;
              } catch (Exception e) {
                  throw new BuildException(e, getLocation());
              }
          }
  
      }
      /**
       *  A string to wait for from the server. 
       *  A subTask &lt;read&gt; tag was found.  Create the object, 
       *  Save it in our list, and return it.
       */
     
      public RExecSubTask createRead() {
          RExecSubTask task = (RExecSubTask) new RExecRead();
          rexecTasks.addElement(task);
          return task;
      }
      /**
       *  Add text to send to the server
       *  A subTask &lt;write&gt; tag was found.  Create the object, 
       *  Save it in our list, and return it.
       */
      public RExecSubTask createWrite() {
          RExecSubTask task = (RExecSubTask) new RExecWrite();
          rexecTasks.addElement(task);
          return task;
      }
      /** 
       *  Verify that all parameters are included. 
       *  Connect and possibly login
       *  Iterate through the list of Reads and writes 
       */
      public void execute() throws BuildException {
          /**  A server name is required to continue */
          if (server == null) {
              throw new BuildException("No Server Specified");
          }
          /**  A userid and password must appear together 
           *   if they appear.  They are not required.
           */
          if (userid == null && password != null) {
              throw new BuildException("No Userid Specified");
          }
          if (password == null && userid != null) {
              throw new BuildException("No Password Specified");
          }
  
          /**  Create the telnet client object */
          rexec = new AntRExecClient();
          try {
              rexec.connect(server, port);
          } catch (IOException e) {
              throw new BuildException("Can't connect to " + server);
          }
          /**  Login if userid and password were specified */
          if (userid != null && password != null) {
              login();
          }
          /**  Process each sub command */
          Enumeration tasksToRun = rexecTasks.elements();
          while (tasksToRun != null && tasksToRun.hasMoreElements()) {
              RExecSubTask task = (RExecSubTask) tasksToRun.nextElement();
              if (task instanceof RExecRead && defaultTimeout != null) {
                  ((RExecRead) task).setDefaultTimeout(defaultTimeout);
              }
              task.execute(rexec);
          }
  
          /** Keep reading input stream until end of it or time-out */
          rexec.waitForEOF(defaultTimeout);
      }
      /**  
       *  Process a 'typical' login.  If it differs, use the read 
       *  and write tasks explicitely
       */
      private void login() {
          if (addCarriageReturn) {
              rexec.sendString("\n", true);
          }
          rexec.waitForString("ogin:");
          rexec.sendString(userid, true);
          rexec.waitForString("assword:");
          rexec.sendString(password, false);
      }
      /**
       * Set the the comand to execute on the server; 
       */
      public void setCommand(String c) { this.command = c; }
      /**
       *  send a carriage return after connecting; optional, defaults to false.
       */
      public void setInitialCR(boolean b) {
          this.addCarriageReturn = b;
      }
      /**
       *  Set the the login password to use
       * required if <tt>userid</tt> is set. 
       */
      public void setPassword(String p) { this.password = p; }
      /**
       *  Set the tcp port to connect to; default is 23.
       */
      public void setPort(int p) { this.port = p; }
      /**
       *  Set the hostname or address of the remote server.
       */
      public void setServer(String m) { this.server = m; }
      /**
       * set a default timeout in seconds to wait for a response, 
       * zero means forever (the default) 
       */
      public void setTimeout(Integer i) {
          this.defaultTimeout = i;
      }
      /**
       * Set the the login id to use on the server; 
       * required if <tt>password</tt> is set. 
       */
      public void setUserid(String u) { this.userid = u; }
  }