1. /*
  2. * Copyright 2001-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.optional;
  18. import java.io.BufferedOutputStream;
  19. import java.io.File;
  20. import java.io.FileOutputStream;
  21. import java.io.IOException;
  22. import java.io.OutputStream;
  23. import java.io.PrintStream;
  24. import java.util.Enumeration;
  25. import java.util.Vector;
  26. import org.apache.tools.ant.BuildException;
  27. import org.apache.tools.ant.Project;
  28. import org.apache.tools.ant.Task;
  29. import org.apache.tools.ant.taskdefs.Execute;
  30. import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
  31. import org.apache.tools.ant.taskdefs.LogOutputStream;
  32. import org.apache.tools.ant.taskdefs.LogStreamHandler;
  33. import org.apache.tools.ant.taskdefs.PumpStreamHandler;
  34. import org.apache.tools.ant.taskdefs.condition.Os;
  35. import org.apache.tools.ant.types.Commandline;
  36. import org.apache.tools.ant.types.Path;
  37. /**
  38. * Invokes the rpm tool to build a Linux installation file.
  39. *
  40. */
  41. public class Rpm extends Task {
  42. /**
  43. * the spec file
  44. */
  45. private String specFile;
  46. /**
  47. * the rpm top dir
  48. */
  49. private File topDir;
  50. /**
  51. * the rpm command to use
  52. */
  53. private String command = "-bb";
  54. /**
  55. * The executable to use for building the packages.
  56. * @since Ant 1.6
  57. */
  58. private String rpmBuildCommand = null;
  59. /**
  60. * clean BUILD directory
  61. */
  62. private boolean cleanBuildDir = false;
  63. /**
  64. * remove spec file
  65. */
  66. private boolean removeSpec = false;
  67. /**
  68. * remove sources
  69. */
  70. private boolean removeSource = false;
  71. /**
  72. * the file to direct standard output from the command
  73. */
  74. private File output;
  75. /**
  76. * the file to direct standard error from the command
  77. */
  78. private File error;
  79. /**
  80. * Execute the task
  81. *
  82. * @throws BuildException is there is a problem in the task execution.
  83. */
  84. public void execute() throws BuildException {
  85. Commandline toExecute = new Commandline();
  86. toExecute.setExecutable(rpmBuildCommand == null
  87. ? guessRpmBuildCommand()
  88. : rpmBuildCommand);
  89. if (topDir != null) {
  90. toExecute.createArgument().setValue("--define");
  91. toExecute.createArgument().setValue("_topdir" + topDir);
  92. }
  93. toExecute.createArgument().setLine(command);
  94. if (cleanBuildDir) {
  95. toExecute.createArgument().setValue("--clean");
  96. }
  97. if (removeSpec) {
  98. toExecute.createArgument().setValue("--rmspec");
  99. }
  100. if (removeSource) {
  101. toExecute.createArgument().setValue("--rmsource");
  102. }
  103. toExecute.createArgument().setValue("SPECS/" + specFile);
  104. ExecuteStreamHandler streamhandler = null;
  105. OutputStream outputstream = null;
  106. OutputStream errorstream = null;
  107. if (error == null && output == null) {
  108. streamhandler = new LogStreamHandler(this, Project.MSG_INFO,
  109. Project.MSG_WARN);
  110. } else {
  111. if (output != null) {
  112. try {
  113. BufferedOutputStream bos
  114. = new BufferedOutputStream(new FileOutputStream(output));
  115. outputstream = new PrintStream(bos);
  116. } catch (IOException e) {
  117. throw new BuildException(e, getLocation());
  118. }
  119. } else {
  120. outputstream = new LogOutputStream(this, Project.MSG_INFO);
  121. }
  122. if (error != null) {
  123. try {
  124. BufferedOutputStream bos
  125. = new BufferedOutputStream(new FileOutputStream(error));
  126. errorstream = new PrintStream(bos);
  127. } catch (IOException e) {
  128. throw new BuildException(e, getLocation());
  129. }
  130. } else {
  131. errorstream = new LogOutputStream(this, Project.MSG_WARN);
  132. }
  133. streamhandler = new PumpStreamHandler(outputstream, errorstream);
  134. }
  135. Execute exe = new Execute(streamhandler, null);
  136. exe.setAntRun(getProject());
  137. if (topDir == null) {
  138. topDir = getProject().getBaseDir();
  139. }
  140. exe.setWorkingDirectory(topDir);
  141. exe.setCommandline(toExecute.getCommandline());
  142. try {
  143. exe.execute();
  144. log("Building the RPM based on the " + specFile + " file");
  145. } catch (IOException e) {
  146. throw new BuildException(e, getLocation());
  147. } finally {
  148. if (output != null) {
  149. try {
  150. outputstream.close();
  151. } catch (IOException e) {
  152. // ignore any secondary error
  153. }
  154. }
  155. if (error != null) {
  156. try {
  157. errorstream.close();
  158. } catch (IOException e) {
  159. // ignore any secondary error
  160. }
  161. }
  162. }
  163. }
  164. /**
  165. * The directory which will have the expected
  166. * subdirectories, SPECS, SOURCES, BUILD, SRPMS ; optional.
  167. * If this isn't specified,
  168. * the <tt>baseDir</tt> value is used
  169. *
  170. * @param td the directory containing the normal RPM directories.
  171. */
  172. public void setTopDir(File td) {
  173. this.topDir = td;
  174. }
  175. /**
  176. * What command to issue to the rpm build tool; optional.
  177. * The default is "-bb"
  178. */
  179. public void setCommand(String c) {
  180. this.command = c;
  181. }
  182. /**
  183. * The name of the spec File to use; required.
  184. */
  185. public void setSpecFile(String sf) {
  186. if ((sf == null) || (sf.trim().equals(""))) {
  187. throw new BuildException("You must specify a spec file", getLocation());
  188. }
  189. this.specFile = sf;
  190. }
  191. /**
  192. * Flag (optional, default=false) to remove
  193. * the generated files in the BUILD directory
  194. */
  195. public void setCleanBuildDir(boolean cbd) {
  196. cleanBuildDir = cbd;
  197. }
  198. /**
  199. * Flag (optional, default=false) to remove the spec file from SPECS
  200. */
  201. public void setRemoveSpec(boolean rs) {
  202. removeSpec = rs;
  203. }
  204. /**
  205. * Flag (optional, default=false)
  206. * to remove the sources after the build.
  207. * See the <tt>--rmsource</tt> option of rpmbuild.
  208. */
  209. public void setRemoveSource(boolean rs) {
  210. removeSource = rs;
  211. }
  212. /**
  213. * Optional file to save stdout to.
  214. */
  215. public void setOutput(File output) {
  216. this.output = output;
  217. }
  218. /**
  219. * Optional file to save stderr to
  220. */
  221. public void setError(File error) {
  222. this.error = error;
  223. }
  224. /**
  225. * The executable to run when building; optional.
  226. * The default is <code>rpmbuild</code>.
  227. *
  228. * @since Ant 1.6
  229. * @param c the rpm build executable
  230. */
  231. public void setRpmBuildCommand(String c) {
  232. this.rpmBuildCommand = c;
  233. }
  234. /**
  235. * Checks whether <code>rpmbuild</code> is on the PATH and returns
  236. * the absolute path to it - falls back to <code>rpm</code>
  237. * otherwise.
  238. *
  239. * @since 1.6
  240. */
  241. protected String guessRpmBuildCommand() {
  242. Vector env = Execute.getProcEnvironment();
  243. String path = null;
  244. for (Enumeration e = env.elements(); e.hasMoreElements();) {
  245. String var = (String) e.nextElement();
  246. if (var.startsWith("PATH=") || var.startsWith("Path=")) {
  247. path = var.substring(6 /* "PATH=".length() + 1 */);
  248. break;
  249. }
  250. }
  251. if (path != null) {
  252. Path p = new Path(getProject(), path);
  253. String[] pElements = p.list();
  254. for (int i = 0; i < pElements.length; i++) {
  255. File f = new File(pElements[i],
  256. "rpmbuild"
  257. + (Os.isFamily("dos") ? ".exe" : ""));
  258. if (f.canRead()) {
  259. return f.getAbsolutePath();
  260. }
  261. }
  262. }
  263. return "rpm";
  264. }
  265. }