1. /*
  2. * Copyright 2000,2002-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.taskdefs;
  18. import java.io.File;
  19. import java.io.IOException;
  20. import org.apache.tools.ant.BuildException;
  21. import org.apache.tools.ant.Project;
  22. import org.apache.tools.ant.Task;
  23. import org.apache.tools.ant.types.Commandline;
  24. /**
  25. * Patches a file by applying a 'diff' file to it; requires "patch" to be
  26. * on the execution path.
  27. *
  28. * @since Ant 1.1
  29. *
  30. * @ant.task category="utility"
  31. */
  32. public class Patch extends Task {
  33. private File originalFile;
  34. private File directory;
  35. private boolean havePatchfile = false;
  36. private Commandline cmd = new Commandline();
  37. /**
  38. * The file to patch; optional if it can be inferred from
  39. * the diff file
  40. * @param file the file to patch
  41. */
  42. public void setOriginalfile(File file) {
  43. originalFile = file;
  44. }
  45. /**
  46. * The name of a file to send the output to, instead of patching
  47. * the file(s) in place; optional.
  48. * @param file the file to send the output to
  49. * @since Ant 1.6
  50. */
  51. public void setDestfile(File file) {
  52. if (file != null) {
  53. cmd.createArgument().setValue("-o");
  54. cmd.createArgument().setFile(file);
  55. }
  56. }
  57. /**
  58. * The file containing the diff output; required.
  59. * @param file the file containing the diff output
  60. */
  61. public void setPatchfile(File file) {
  62. if (!file.exists()) {
  63. throw new BuildException("patchfile " + file + " doesn\'t exist",
  64. getLocation());
  65. }
  66. cmd.createArgument().setValue("-i");
  67. cmd.createArgument().setFile(file);
  68. havePatchfile = true;
  69. }
  70. /**
  71. * flag to create backups; optional, default=false
  72. * @param backups if true create backups
  73. */
  74. public void setBackups(boolean backups) {
  75. if (backups) {
  76. cmd.createArgument().setValue("-b");
  77. }
  78. }
  79. /**
  80. * flag to ignore whitespace differences; default=false
  81. * @param ignore if true ignore whitespace differences
  82. */
  83. public void setIgnorewhitespace(boolean ignore) {
  84. if (ignore) {
  85. cmd.createArgument().setValue("-l");
  86. }
  87. }
  88. /**
  89. * Strip the smallest prefix containing <i>num</i> leading slashes
  90. * from filenames.
  91. *
  92. * <p>patch's <i>-p</i> option.
  93. * @param num number of lines to strip
  94. * @exception BuildException if num is < 0, or other errors
  95. */
  96. public void setStrip(int num) throws BuildException {
  97. if (num < 0) {
  98. throw new BuildException("strip has to be >= 0", getLocation());
  99. }
  100. cmd.createArgument().setValue("-p" + num);
  101. }
  102. /**
  103. * Work silently unless an error occurs; optional, default=false
  104. * @param q if true suppress set the -s option on the patch command
  105. */
  106. public void setQuiet(boolean q) {
  107. if (q) {
  108. cmd.createArgument().setValue("-s");
  109. }
  110. }
  111. /**
  112. * Assume patch was created with old and new files swapped; optional,
  113. * default=false
  114. * @param r if true set the -R option on the patch command
  115. */
  116. public void setReverse(boolean r) {
  117. if (r) {
  118. cmd.createArgument().setValue("-R");
  119. }
  120. }
  121. /**
  122. * The directory to run the patch command in, defaults to the
  123. * project's base directory.
  124. * @param directory the directory to run the patch command in
  125. * @since Ant 1.5
  126. */
  127. public void setDir(File directory) {
  128. this.directory = directory;
  129. }
  130. /**
  131. * execute patch
  132. * @throws BuildException when it all goes a bit pear shaped
  133. */
  134. public void execute() throws BuildException {
  135. if (!havePatchfile) {
  136. throw new BuildException("patchfile argument is required",
  137. getLocation());
  138. }
  139. Commandline toExecute = (Commandline) cmd.clone();
  140. toExecute.setExecutable("patch");
  141. if (originalFile != null) {
  142. toExecute.createArgument().setFile(originalFile);
  143. }
  144. Execute exe = new Execute(new LogStreamHandler(this, Project.MSG_INFO,
  145. Project.MSG_WARN),
  146. null);
  147. exe.setCommandline(toExecute.getCommandline());
  148. if (directory != null) {
  149. if (directory.exists() && directory.isDirectory()) {
  150. exe.setWorkingDirectory(directory);
  151. } else if (!directory.isDirectory()) {
  152. throw new BuildException(directory + " is not a directory.",
  153. getLocation());
  154. } else {
  155. throw new BuildException("directory " + directory
  156. + " doesn\'t exist", getLocation());
  157. }
  158. } else {
  159. exe.setWorkingDirectory(getProject().getBaseDir());
  160. }
  161. log(toExecute.describeCommand(), Project.MSG_VERBOSE);
  162. try {
  163. exe.execute();
  164. } catch (IOException e) {
  165. throw new BuildException(e, getLocation());
  166. }
  167. }
  168. }