001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.nbbuild;
043:
044: import java.io.BufferedReader;
045: import java.io.File;
046: import java.io.FileInputStream;
047: import java.io.FileOutputStream;
048: import java.io.IOException;
049: import java.io.InputStream;
050: import java.io.InputStreamReader;
051: import java.io.OutputStream;
052: import java.io.OutputStreamWriter;
053: import java.io.PrintWriter;
054: import java.util.ArrayList;
055: import java.util.Collections;
056: import java.util.List;
057: import java.util.StringTokenizer;
058: import java.util.regex.Matcher;
059: import java.util.regex.Pattern;
060: import org.apache.tools.ant.BuildException;
061: import org.apache.tools.ant.Project;
062: import org.apache.tools.ant.Task;
063:
064: /**
065: * Increments specification versions of all specified modules,
066: * in the trunk or in a branch, in a regulated manner.
067: * @author Jesse Glick
068: */
069: public final class IncrementSpecificationVersions extends Task {
070:
071: private File nbroot;
072: private List<String> modules;
073: private int stickyLevel = -1;
074:
075: public IncrementSpecificationVersions() {
076: }
077:
078: public void setNbroot(File f) {
079: nbroot = f;
080: }
081:
082: public void setModules(String m) {
083: modules = new ArrayList<String>();
084: for (Object o : Collections.list(new StringTokenizer(m, ", "))) {
085: modules.add((String) o);
086: }
087: }
088:
089: public void setBranch(boolean b) {
090: setStickyLevel(b ? 2 : 1);
091: }
092:
093: /** Number of digits from the begining that are supposed to
094: * stay the same
095: */
096: public void setStickyLevel(int stickyLevel) {
097: if (this .stickyLevel != -1) {
098: throw new BuildException(
099: "Only one stickyLevel or branch attribute can be used!");
100: }
101:
102: this .stickyLevel = stickyLevel;
103: }
104:
105: public void execute() throws BuildException {
106: if (nbroot == null || modules == null) {
107: throw new BuildException(
108: "Missing params 'nbroot' or 'modules'",
109: getLocation());
110: }
111: MODULE: for (String module : modules) {
112: File dir = new File(nbroot, module.replace('/',
113: File.separatorChar));
114: if (!dir.isDirectory()) {
115: log("No such directory " + dir + "; skipping",
116: Project.MSG_WARN);
117: continue;
118: }
119: try {
120: File pp = new File(dir, "nbproject"
121: + File.separatorChar + "project.properties");
122: if (pp.isFile()) {
123: String[] lines = gulp(pp, "ISO-8859-1");
124: for (int i = 0; i < lines.length; i++) {
125: Matcher m1 = Pattern.compile(
126: "(spec\\.version\\.base=)(.+)")
127: .matcher(lines[i]);
128: if (m1.matches()) {
129: String old = m1.group(2);
130: String nue = increment(old, stickyLevel,
131: false);
132: if (nue != null) {
133: lines[i] = m1.group(1) + nue;
134: spit(pp, "ISO-8859-1", lines);
135: log("Incrementing " + old + " -> "
136: + nue + " in " + pp);
137: } else {
138: log(
139: pp
140: + ":"
141: + (i + 1)
142: + ": Unsupported old version number "
143: + old
144: + " (must be x.y.0 in trunk or x.y.z in branch); skipping",
145: Project.MSG_WARN);
146: }
147: continue MODULE;
148: }
149: }
150: } else {
151: if (!new File(dir, "nbproject" + File.separatorChar
152: + "project.xml").isFile()) {
153: log("No such file " + pp
154: + "; unprojectized module?",
155: Project.MSG_WARN);
156: }
157: }
158: File mf = new File(dir, "manifest.mf");
159: if (mf.isFile()) {
160: String[] lines = gulp(mf, "UTF-8");
161: for (int i = 0; i < lines.length; i++) {
162: Matcher m1 = Pattern
163: .compile(
164: "(OpenIDE-Module-Specification-Version: )(.+)")
165: .matcher(lines[i]);
166: if (m1.matches()) {
167: String old = m1.group(2);
168: String nue = increment(old, stickyLevel,
169: true);
170: if (nue != null) {
171: lines[i] = m1.group(1) + nue;
172: spit(mf, "UTF-8", lines);
173: log("Incrementing " + old + " -> "
174: + nue + " in " + mf);
175: } else {
176: log(
177: mf
178: + ":"
179: + (i + 1)
180: + ": Unsupported old version number "
181: + old
182: + " (must be x.y in trunk or x.y.z in branch); skipping",
183: Project.MSG_WARN);
184: }
185: continue MODULE;
186: }
187: }
188: } else {
189: log("No such file " + mf + "; not a real module?",
190: Project.MSG_WARN);
191: }
192: log("Could not find any specification version in "
193: + dir + "; skipping", Project.MSG_WARN);
194: } catch (IOException e) {
195: throw new BuildException("While processing " + dir
196: + ": " + e, e, getLocation());
197: }
198: }
199: }
200:
201: /** Does the increment of the specification version to new version.
202: * @return the new version or null if the increment fails
203: */
204: static String increment(String old, int stickyLevel,
205: boolean manifest) throws NumberFormatException {
206: String nue = null;
207:
208: switch (stickyLevel) {
209: case 1: // trunk
210: if (manifest) {
211: Matcher mC = Pattern.compile("([0-9]+\\.)([0-9]+)")
212: .matcher(old);
213: Matcher mW1 = Pattern.compile("([0-9]+)").matcher(old);
214: Matcher mW2 = Pattern.compile(
215: "([0-9]+\\.)([0-9]+)\\.([0-9\\.]+)").matcher(
216: old);
217: if (mC.matches()) { // Correct e.g 1.0 -> 1.1
218: nue = mC.group(1)
219: + (Integer.parseInt(mC.group(2)) + 1);
220: } else if (mW1.matches()) { // Wrong e.g 1 -> 1.1
221: nue = mW1.group(1) + ".1";
222: } else if (mW2.matches()) { // Wrong e.g 1.2.4.5.6.7 => 1.3
223: nue = mW2.group(1)
224: + (Integer.parseInt(mW2.group(2)) + 1);
225: }
226: } else {
227: Matcher mC = Pattern.compile(
228: "([0-9]+\\.)([0-9]+)(\\.0)").matcher(old);
229: Matcher mW1 = Pattern.compile("([0-9]+)").matcher(old);
230: Matcher mW2 = Pattern.compile("([0-9]+\\.)([0-9]+)")
231: .matcher(old);
232: Matcher mW3 = Pattern.compile(
233: "([0-9]+\\.)([0-9]+)\\.([0-9\\.]+)").matcher(
234: old);
235:
236: if (mC.matches()) { // Correct 1.1.0 -> 1.2.0
237: nue = mC.group(1)
238: + (Integer.parseInt(mC.group(2)) + 1)
239: + mC.group(3);
240: } else if (mW1.matches()) { // Wrong 1 -> 1.1.0
241: nue = mW1.group(1) + ".1.0";
242: } else if (mW2.matches()) { // Wrong 1.1 -> 1.2.0
243: nue = mW2.group(1)
244: + (Integer.parseInt(mW2.group(2)) + 1)
245: + ".0";
246: } else if (mW3.matches()) { // Wrong 1.2.3.4.5.6 -> 1.3.0
247: nue = mW3.group(1)
248: + (Integer.parseInt(mW3.group(2)) + 1)
249: + ".0";
250: }
251: }
252: break;
253: case 2: // branch
254: if (manifest) {
255: Matcher mC1 = Pattern.compile(
256: "([0-9]+\\.[0-9]+\\.)([0-9]+)").matcher(old);
257: Matcher mC2 = Pattern.compile("([0-9]+\\.[0-9]+)")
258: .matcher(old);
259: Matcher mW1 = Pattern.compile("([0-9]+)").matcher(old);
260: Matcher mW2 = Pattern.compile(
261: "([0-9]+\\.[0-9]+\\.)([0-9]+)\\.([0-9\\.]+)")
262: .matcher(old);
263: if (mC1.matches()) { // Correct 1.2.3 -> 1.2.4
264: nue = mC1.group(1)
265: + (Integer.parseInt(mC1.group(2)) + 1);
266: } else if (mC2.matches()) { // Correct 1.2 -> 1.2.1
267: nue = mC2.group(1) + ".1";
268: } else if (mW1.matches()) { // Wrong 1 -> 1.0.1
269: nue = mW1.group(1) + ".0.1";
270: } else if (mW2.matches()) { // Wrong 1.2.3.4.5.6 -> 1.2.4
271: nue = mW2.group(1)
272: + (Integer.parseInt(mW2.group(2)) + 1);
273: }
274:
275: } else {
276: Matcher mC = Pattern.compile(
277: "([0-9]+\\.[0-9]+\\.)([0-9]+)").matcher(old);
278: Matcher mW1 = Pattern.compile("([0-9]+)").matcher(old);
279: Matcher mW2 = Pattern.compile("([0-9]+\\.[0-9]+)")
280: .matcher(old);
281: Matcher mW3 = Pattern.compile(
282: "([0-9]+\\.[0-9]+\\.)([0-9]+)\\.([0-9\\.]+)")
283: .matcher(old);
284: if (mC.matches()) { // Correct 1.2.3 -> 1.2.4
285: nue = mC.group(1)
286: + (Integer.parseInt(mC.group(2)) + 1);
287: } else if (mW1.matches()) { // Wrong 1 -> 1.0.1
288: nue = mW1.group(1) + ".0.1";
289: } else if (mW2.matches()) { // Wrong 1.2 -> 1.2.1
290: nue = mW2.group(1) + ".1";
291: } else if (mW3.matches()) { // Wrong 1.2.3.4.5.6 -> 1.2.4
292: nue = mW3.group(1)
293: + (Integer.parseInt(mW3.group(2)) + 1);
294: }
295: }
296: break;
297: default:
298: if (stickyLevel < 1) {
299: throw new BuildException("Invalid sticky level: "
300: + stickyLevel);
301: }
302: int[] segments = new int[stickyLevel + 1];
303: StringTokenizer tok = new StringTokenizer(old, ".");
304: for (int i = 0; i < segments.length
305: && tok.hasMoreElements(); i++) {
306: segments[i] = Integer.parseInt(tok.nextToken());
307: }
308: segments[stickyLevel]++;
309: nue = "";
310: String pref = "";
311: for (int i = 0; i < segments.length; i++) {
312: nue += pref;
313: nue += segments[i];
314: pref = ".";
315: }
316: break;
317: }
318:
319: return nue;
320: }
321:
322: private static String[] gulp(File file, String enc)
323: throws IOException {
324: InputStream is = new FileInputStream(file);
325: try {
326: BufferedReader r = new BufferedReader(
327: new InputStreamReader(is, enc));
328: List<String> l = new ArrayList<String>();
329: String line;
330: while ((line = r.readLine()) != null) {
331: l.add(line);
332: }
333: return l.toArray(new String[l.size()]);
334: } finally {
335: is.close();
336: }
337: }
338:
339: private static void spit(File file, String enc, String[] lines)
340: throws IOException {
341: OutputStream os = new FileOutputStream(file);
342: try {
343: PrintWriter w = new PrintWriter(new OutputStreamWriter(os,
344: enc));
345: for (String line : lines) {
346: w.println(line);
347: }
348: w.flush();
349: } finally {
350: os.close();
351: }
352: }
353:
354: }
|