001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.tools.ant.taskdefs;
019:
020: import java.io.File;
021: import java.io.FileInputStream;
022: import java.io.FileOutputStream;
023: import java.io.IOException;
024: import java.util.Properties;
025: import org.apache.tools.ant.BuildException;
026: import org.apache.tools.ant.Task;
027: import org.apache.tools.ant.Project;
028: import org.apache.tools.ant.util.FileUtils;
029:
030: /**
031: * Read, increment, and write a build number in a file
032: * It will first
033: * attempt to read a build number from a file, then set the property
034: * "build.number" to the value that was read in (or 0 if no such value). Then
035: * it will increment the build number by one and write it back out into the
036: * file.
037: *
038: * @since Ant 1.5
039: * @ant.task name="buildnumber"
040: */
041: public class BuildNumber extends Task {
042: /**
043: * The name of the property in which the build number is stored.
044: */
045: private static final String DEFAULT_PROPERTY_NAME = "build.number";
046:
047: /** The default filename to use if no file specified. */
048: private static final String DEFAULT_FILENAME = DEFAULT_PROPERTY_NAME;
049:
050: private static final FileUtils FILE_UTILS = FileUtils
051: .getFileUtils();
052:
053: /** The File in which the build number is stored. */
054: private File myFile;
055:
056: /**
057: * The file in which the build number is stored. Defaults to
058: * "build.number" if not specified.
059: *
060: * @param file the file in which build number is stored.
061: */
062: public void setFile(final File file) {
063: myFile = file;
064: }
065:
066: /**
067: * Run task.
068: *
069: * @exception BuildException if an error occurs
070: */
071: public void execute() throws BuildException {
072: File savedFile = myFile; // may be altered in validate
073:
074: validate();
075:
076: final Properties properties = loadProperties();
077: final int buildNumber = getBuildNumber(properties);
078:
079: properties.put(DEFAULT_PROPERTY_NAME, String
080: .valueOf(buildNumber + 1));
081:
082: // Write the properties file back out
083: FileOutputStream output = null;
084:
085: try {
086: output = new FileOutputStream(myFile);
087:
088: final String header = "Build Number for ANT. Do not edit!";
089:
090: properties.store(output, header);
091: } catch (final IOException ioe) {
092: final String message = "Error while writing " + myFile;
093:
094: throw new BuildException(message, ioe);
095: } finally {
096: if (null != output) {
097: try {
098: output.close();
099: } catch (final IOException ioe) {
100: log("error closing output stream " + ioe,
101: Project.MSG_ERR);
102: }
103: }
104: myFile = savedFile;
105: }
106:
107: //Finally set the property
108: getProject().setNewProperty(DEFAULT_PROPERTY_NAME,
109: String.valueOf(buildNumber));
110: }
111:
112: /**
113: * Utility method to retrieve build number from properties object.
114: *
115: * @param properties the properties to retrieve build number from
116: * @return the build number or if no number in properties object
117: * @throws BuildException if build.number property is not an integer
118: */
119: private int getBuildNumber(final Properties properties)
120: throws BuildException {
121: final String buildNumber = properties.getProperty(
122: DEFAULT_PROPERTY_NAME, "0").trim();
123:
124: // Try parsing the line into an integer.
125: try {
126: return Integer.parseInt(buildNumber);
127: } catch (final NumberFormatException nfe) {
128: final String message = myFile
129: + " contains a non integer build number: "
130: + buildNumber;
131: throw new BuildException(message, nfe);
132: }
133: }
134:
135: /**
136: * Utility method to load properties from file.
137: *
138: * @return the loaded properties
139: * @throws BuildException
140: */
141: private Properties loadProperties() throws BuildException {
142: FileInputStream input = null;
143:
144: try {
145: final Properties properties = new Properties();
146:
147: input = new FileInputStream(myFile);
148: properties.load(input);
149: return properties;
150: } catch (final IOException ioe) {
151: throw new BuildException(ioe);
152: } finally {
153: if (null != input) {
154: try {
155: input.close();
156: } catch (final IOException ioe) {
157: log("error closing input stream " + ioe,
158: Project.MSG_ERR);
159: }
160: }
161: }
162: }
163:
164: /**
165: * Validate that the task parameters are valid.
166: *
167: * @throws BuildException if parameters are invalid
168: */
169: private void validate() throws BuildException {
170: if (null == myFile) {
171: myFile = FILE_UTILS.resolveFile(getProject().getBaseDir(),
172: DEFAULT_FILENAME);
173: }
174:
175: if (!myFile.exists()) {
176: try {
177: FILE_UTILS.createNewFile(myFile);
178: } catch (final IOException ioe) {
179: final String message = myFile
180: + " doesn't exist and new file can't be created.";
181: throw new BuildException(message, ioe);
182: }
183: }
184:
185: if (!myFile.canRead()) {
186: final String message = "Unable to read from " + myFile
187: + ".";
188: throw new BuildException(message);
189: }
190:
191: if (!myFile.canWrite()) {
192: final String message = "Unable to write to " + myFile + ".";
193: throw new BuildException(message);
194: }
195: }
196: }
|