Home » apache-ant-1.7.1-src » org.apache.tools » ant » taskdefs » [javadoc | source]
    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one or more
    3    *  contributor license agreements.  See the NOTICE file distributed with
    4    *  this work for additional information regarding copyright ownership.
    5    *  The ASF licenses this file to You under the Apache License, Version 2.0
    6    *  (the "License"); you may not use this file except in compliance with
    7    *  the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    *  Unless required by applicable law or agreed to in writing, software
   12    *  distributed under the License is distributed on an "AS IS" BASIS,
   13    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    *  See the License for the specific language governing permissions and
   15    *  limitations under the License.
   16    *
   17    */
   18   package org.apache.tools.ant.taskdefs;
   19   
   20   import java.io.File;
   21   import java.io.UnsupportedEncodingException;
   22   
   23   import org.apache.tools.ant.Task;
   24   import org.apache.tools.ant.types.Path;
   25   import org.apache.tools.ant.BuildException;
   26   import org.apache.tools.ant.launch.Locator;
   27   import org.apache.tools.ant.util.FileUtils;
   28   
   29   /**
   30    * Converts a Path into a property suitable as a Manifest classpath.
   31    *
   32    * @since Ant 1.7
   33    *
   34    * @ant.task category="property"
   35    */
   36   public class ManifestClassPath extends Task {
   37   
   38       /** The property name to hold the classpath value. */
   39       private String name;
   40   
   41       /** The directory the classpath will be relative from. */
   42       private File dir;
   43   
   44       /** The maximum parent directory level to traverse. */
   45       private int maxParentLevels = 2;
   46   
   47       /** The classpath to convert. */
   48       private Path path;
   49   
   50       /**
   51        * Sets a property, which must not already exist, with a space
   52        * separated list of files and directories relative to the jar
   53        * file's parent directory.
   54        */
   55       public void execute() {
   56           if (name == null) {
   57             throw new BuildException("Missing 'property' attribute!");
   58           }
   59           if (dir == null) {
   60             throw new BuildException("Missing 'jarfile' attribute!");
   61           }
   62           if (getProject().getProperty(name) != null) {
   63             throw new BuildException("Property '" + name + "' already set!");
   64           }
   65           if (path == null) {
   66               throw new BuildException("Missing nested <classpath>!");
   67           }
   68   
   69           // Normalize the reference directory (containing the jar)
   70           final FileUtils fileUtils = FileUtils.getFileUtils();
   71           dir = fileUtils.normalize(dir.getAbsolutePath());
   72   
   73           // Create as many directory prefixes as parent levels to traverse,
   74           // in addition to the reference directory itself
   75           File currDir = dir;
   76           String[] dirs = new String[maxParentLevels + 1];
   77           for (int i = 0; i < maxParentLevels + 1; ++i) {
   78               dirs[i] = currDir.getAbsolutePath() + File.separatorChar;
   79               currDir = currDir.getParentFile();
   80               if (currDir == null) {
   81                   maxParentLevels = i + 1;
   82                   break;
   83               }
   84           }
   85   
   86           String[] elements = path.list();
   87           StringBuffer buffer = new StringBuffer();
   88           StringBuffer element = new StringBuffer();
   89           for (int i = 0; i < elements.length; ++i) {
   90               // Normalize the current file
   91               File pathEntry = new File(elements[i]);
   92               pathEntry = fileUtils.normalize(pathEntry.getAbsolutePath());
   93               String fullPath = pathEntry.getAbsolutePath();
   94   
   95               // Find the longest prefix shared by the current file
   96               // and the reference directory.
   97               String relPath = null;
   98               for (int j = 0; j <= maxParentLevels; ++j) {
   99                   String dir = dirs[j];
  100                   if (!fullPath.startsWith(dir)) {
  101                       continue;
  102                   }
  103   
  104                   // We have a match! Add as many ../ as parent
  105                   // directory traversed to get the relative path
  106                   element.setLength(0);
  107                   for (int k = 0; k < j; ++k) {
  108                       element.append("..");
  109                       element.append(File.separatorChar);
  110                   }
  111                   element.append(fullPath.substring(dir.length()));
  112                   relPath = element.toString();
  113                   break;
  114               }
  115   
  116               // No match, so bail out!
  117               if (relPath == null) {
  118                   throw new BuildException(
  119                       "No suitable relative path from "
  120                       + dir + " to " + fullPath);
  121               }
  122   
  123               // Manifest's ClassPath: attribute always uses forward
  124               // slashes '/', and is space-separated. Ant will properly
  125               // format it on 72 columns with proper line continuation
  126               if (File.separatorChar != '/') {
  127                   relPath = relPath.replace(File.separatorChar, '/');
  128               }
  129               if (pathEntry.isDirectory()) {
  130                   relPath = relPath + '/';
  131               }
  132               try {
  133                   relPath = Locator.encodeURI(relPath);
  134               } catch (UnsupportedEncodingException exc) {
  135                   throw new BuildException(exc);
  136               }
  137               buffer.append(relPath);
  138               buffer.append(' ');
  139           }
  140   
  141           // Finally assign the property with the manifest classpath
  142           getProject().setNewProperty(name, buffer.toString().trim());
  143       }
  144   
  145       /**
  146        * Sets the property name to hold the classpath value.
  147        *
  148        * @param  name the property name
  149        */
  150       public void setProperty(String name) {
  151           this.name = name;
  152       }
  153   
  154       /**
  155        * The JAR file to contain the classpath attribute in its manifest.
  156        *
  157        * @param  jarfile the JAR file. Need not exist yet, but its parent
  158        *         directory must exist on the other hand.
  159        */
  160       public void setJarFile(File jarfile) {
  161           File parent = jarfile.getParentFile();
  162           if (!parent.isDirectory()) {
  163               throw new BuildException("Jar's directory not found: " + parent);
  164           }
  165           this.dir = parent;
  166       }
  167   
  168       /**
  169        * Sets the maximum parent directory levels allowed when computing
  170        * a relative path.
  171        *
  172        * @param  levels the max level. Defaults to 2.
  173        */
  174       public void setMaxParentLevels(int levels) {
  175           this.maxParentLevels = levels;
  176       }
  177   
  178       /**
  179        * Adds the classpath to convert.
  180        *
  181        * @param  path the classpath to convert.
  182        */
  183       public void addClassPath(Path path) {
  184           this.path = path;
  185       }
  186   
  187   }

Save This Page
Home » apache-ant-1.7.1-src » org.apache.tools » ant » taskdefs » [javadoc | source]