You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

ManifestClassPath.java 6.6 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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. import java.io.File;
  20. import java.io.UnsupportedEncodingException;
  21. import org.apache.tools.ant.Task;
  22. import org.apache.tools.ant.types.Path;
  23. import org.apache.tools.ant.BuildException;
  24. import org.apache.tools.ant.launch.Locator;
  25. import org.apache.tools.ant.util.FileUtils;
  26. /**
  27. * Converts a Path into a property suitable as a Manifest classpath.
  28. *
  29. * @since Ant 1.7
  30. *
  31. * @ant.task category="property"
  32. */
  33. public class ManifestClassPath extends Task {
  34. /** The property name to hold the classpath value. */
  35. private String name;
  36. /** The directory the classpath will be relative from. */
  37. private File dir;
  38. /** The maximum parent directory level to traverse. */
  39. private int maxParentLevels = 2;
  40. /** The classpath to convert. */
  41. private Path path;
  42. /**
  43. * Sets a property, which must not already exist, with a space
  44. * separated list of files and directories relative to the jar
  45. * file's parent directory.
  46. */
  47. public void execute() {
  48. if (name == null) {
  49. throw new BuildException("Missing 'property' attribute!");
  50. }
  51. if (dir == null) {
  52. throw new BuildException("Missing 'jarfile' attribute!");
  53. }
  54. if (getProject().getProperty(name) != null) {
  55. throw new BuildException("Property '" + name + "' already set!");
  56. }
  57. if (path == null) {
  58. throw new BuildException("Missing nested <classpath>!");
  59. }
  60. // Normalize the reference directory (containing the jar)
  61. final FileUtils fileUtils = FileUtils.getFileUtils();
  62. dir = fileUtils.normalize(dir.getAbsolutePath());
  63. // Create as many directory prefixes as parent levels to traverse,
  64. // in addition to the reference directory itself
  65. File currDir = dir;
  66. String[] dirs = new String[maxParentLevels + 1];
  67. for (int i = 0; i < maxParentLevels + 1; ++i) {
  68. dirs[i] = currDir.getAbsolutePath();
  69. if (!dirs[i].equals("" + File.separatorChar)) {
  70. dirs[i] = dirs[i] + File.separatorChar;
  71. }
  72. currDir = currDir.getParentFile();
  73. if (currDir == null) {
  74. maxParentLevels = i + 1;
  75. break;
  76. }
  77. }
  78. String[] elements = path.list();
  79. StringBuffer buffer = new StringBuffer();
  80. StringBuffer element = new StringBuffer();
  81. for (int i = 0; i < elements.length; ++i) {
  82. // Normalize the current file
  83. File pathEntry = new File(elements[i]);
  84. pathEntry = fileUtils.normalize(pathEntry.getAbsolutePath());
  85. String fullPath = pathEntry.getAbsolutePath();
  86. // Find the longest prefix shared by the current file
  87. // and the reference directory.
  88. String relPath = null;
  89. for (int j = 0; j <= maxParentLevels && j < dirs.length; ++j) {
  90. String dir = dirs[j];
  91. if (!fullPath.startsWith(dir)) {
  92. continue;
  93. }
  94. // We have a match! Add as many ../ as parent
  95. // directory traversed to get the relative path
  96. element.setLength(0);
  97. for (int k = 0; k < j; ++k) {
  98. element.append("..");
  99. element.append(File.separatorChar);
  100. }
  101. element.append(fullPath.substring(dir.length()));
  102. relPath = element.toString();
  103. break;
  104. }
  105. // No match, so bail out!
  106. if (relPath == null) {
  107. throw new BuildException(
  108. "No suitable relative path from "
  109. + dir + " to " + fullPath);
  110. }
  111. // Manifest's ClassPath: attribute always uses forward
  112. // slashes '/', and is space-separated. Ant will properly
  113. // format it on 72 columns with proper line continuation
  114. if (File.separatorChar != '/') {
  115. relPath = relPath.replace(File.separatorChar, '/');
  116. }
  117. if (pathEntry.isDirectory()) {
  118. relPath = relPath + '/';
  119. }
  120. try {
  121. relPath = Locator.encodeURI(relPath);
  122. } catch (UnsupportedEncodingException exc) {
  123. throw new BuildException(exc);
  124. }
  125. buffer.append(relPath);
  126. buffer.append(' ');
  127. }
  128. // Finally assign the property with the manifest classpath
  129. getProject().setNewProperty(name, buffer.toString().trim());
  130. }
  131. /**
  132. * Sets the property name to hold the classpath value.
  133. *
  134. * @param name the property name
  135. */
  136. public void setProperty(String name) {
  137. this.name = name;
  138. }
  139. /**
  140. * The JAR file to contain the classpath attribute in its manifest.
  141. *
  142. * @param jarfile the JAR file. Need not exist yet, but its parent
  143. * directory must exist on the other hand.
  144. */
  145. public void setJarFile(File jarfile) {
  146. File parent = jarfile.getParentFile();
  147. if (!parent.isDirectory()) {
  148. throw new BuildException("Jar's directory not found: " + parent);
  149. }
  150. this.dir = parent;
  151. }
  152. /**
  153. * Sets the maximum parent directory levels allowed when computing
  154. * a relative path.
  155. *
  156. * @param levels the max level. Defaults to 2.
  157. */
  158. public void setMaxParentLevels(int levels) {
  159. this.maxParentLevels = levels;
  160. }
  161. /**
  162. * Adds the classpath to convert.
  163. *
  164. * @param path the classpath to convert.
  165. */
  166. public void addClassPath(Path path) {
  167. this.path = path;
  168. }
  169. }