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.File;
045: import java.io.FileInputStream;
046: import java.io.FileWriter;
047: import java.io.IOException;
048: import java.io.InputStream;
049: import java.util.ArrayList;
050: import java.util.List;
051: import org.apache.tools.ant.BuildException;
052: import org.apache.tools.ant.FileScanner;
053: import org.apache.tools.ant.Project;
054: import org.apache.tools.ant.Task;
055: import org.apache.tools.ant.taskdefs.Ant;
056: import org.apache.tools.ant.types.FileSet;
057: import org.apache.tools.ant.util.FileUtils;
058:
059: /** Assistent in changing of build scripts.
060: *
061: * @author Jaroslav Tulach
062: */
063: public class FixDependencies extends Task {
064: /** Replace*/
065: private List<Replace> replaces = new ArrayList<Replace>();
066: /** files to fix */
067: private FileSet set;
068: /** verify target */
069: private String target;
070: /** clean target */
071: private String clean;
072: /** relative path from module file to build script to use for verification */
073: private String ant;
074: /** trip only changed */
075: private boolean onlyChanged;
076: /** fail on error */
077: private boolean fail;
078:
079: /** tasks to be executed */
080:
081: /** Initialize. */
082: public FixDependencies() {
083: }
084:
085: public Replace createReplace() {
086: Replace r = new Replace();
087: replaces.add(r);
088: return r;
089: }
090:
091: public FileSet createFileset() throws BuildException {
092: if (this .set != null)
093: throw new BuildException("Only one file set is allowed");
094: this .set = new FileSet();
095: return this .set;
096: }
097:
098: public void setBuildTarget(String s) {
099: target = s;
100: }
101:
102: public void setCleanTarget(String s) {
103: clean = s;
104: }
105:
106: public void setAntFile(String r) {
107: ant = r;
108: }
109:
110: public void setStripOnlyChanged(boolean b) {
111: onlyChanged = b;
112: }
113:
114: public void setFailOnError(boolean b) {
115: fail = b;
116: }
117:
118: public void execute() throws org.apache.tools.ant.BuildException {
119: FileScanner scan = this .set.getDirectoryScanner(getProject());
120: File dir = scan.getBasedir();
121: for (String kid : scan.getIncludedFiles()) {
122: File xml = new File(dir, kid);
123: if (!xml.exists())
124: throw new BuildException("File does not exist: " + xml,
125: getLocation());
126:
127: log("Fixing " + xml, Project.MSG_INFO);
128:
129: File script = null;
130: Ant task = null;
131: Ant cleanTask = null;
132: if (ant != null && target != null) {
133: task = (org.apache.tools.ant.taskdefs.Ant) getProject()
134: .createTask("ant");
135: script = FileUtils.getFileUtils().resolveFile(xml, ant);
136: if (!script.exists()) {
137: String msg = "Skipping. Cannot find file " + ant
138: + " from + " + xml;
139: if (fail) {
140: throw new BuildException(msg);
141: }
142: log(msg, Project.MSG_ERR);
143: continue;
144: }
145: task.setAntfile(script.getPath());
146: task.setDir(script.getParentFile());
147: task.setTarget(target);
148: if (clean != null) {
149: cleanTask = (Ant) getProject().createTask("ant");
150: cleanTask.setAntfile(script.getPath());
151: cleanTask.setDir(script.getParentFile());
152: cleanTask.setTarget(clean);
153: }
154:
155: try {
156: // before we do anything else, let's verify that we build
157: if (cleanTask != null) {
158: log("Cleaning " + clean + " in " + script,
159: org.apache.tools.ant.Project.MSG_INFO);
160: cleanTask.execute();
161: }
162: log("Sanity check executes " + target + " in "
163: + script,
164: org.apache.tools.ant.Project.MSG_INFO);
165: task.execute();
166: } catch (BuildException ex) {
167: if (fail) {
168: throw ex;
169: }
170:
171: log("Skipping. Could not execute " + target
172: + " in " + script,
173: org.apache.tools.ant.Project.MSG_ERR);
174: continue;
175: }
176: }
177:
178: try {
179: boolean change = fix(xml);
180: if (onlyChanged && !change) {
181: continue;
182: }
183: simplify(xml, script, task, cleanTask);
184: } catch (IOException ex) {
185: throw new BuildException(ex, getLocation());
186: }
187: }
188: }
189:
190: /** Modifies the xml file to replace dependencies wiht new ones.
191: * @return true if there was a change in the file
192: */
193: private boolean fix(File file) throws IOException, BuildException {
194: int s = (int) file.length();
195: byte[] data = new byte[s];
196: InputStream is = new FileInputStream(file);
197: if (s != is.read(data)) {
198: is.close();
199: throw new BuildException("Cannot read " + file);
200: }
201: is.close();
202:
203: String stream = new String(data);
204: String old = stream;
205: data = null;
206:
207: for (Replace r : replaces) {
208: int idx = stream.indexOf("<code-name-base>"
209: + r.codeNameBase + "</code-name-base>");
210: if (idx == -1)
211: continue;
212:
213: int from = stream.lastIndexOf("<dependency>", idx);
214: if (from == -1)
215: throw new BuildException(
216: "No <dependency> tag before index " + idx);
217: int after = stream.indexOf("</dependency>", idx);
218: if (after == -1)
219: throw new BuildException(
220: "No </dependency> tag after index " + idx);
221: after = findNonSpace(stream, after
222: + "</dependency>".length());
223:
224: String remove = stream.substring(from, after);
225: if (r.addCompileTime
226: && remove.indexOf("compile-dependency") == -1) {
227: int fromAfter = "<dependency>".length();
228: int nonSpace = findNonSpace(remove, fromAfter);
229: String spaces = remove.substring(fromAfter, nonSpace);
230: remove = remove.substring(0, fromAfter) + spaces
231: + "<compile-dependency/>"
232: + remove.substring(fromAfter);
233: }
234:
235: StringBuffer sb = new StringBuffer();
236: sb.append(stream.substring(0, from));
237:
238: for (Module m : r.modules) {
239: if (stream.indexOf("<code-name-base>" + m.codeNameBase
240: + "</code-name-base>") != -1) {
241: continue;
242: }
243:
244: int beg = remove.indexOf(r.codeNameBase);
245: int aft = beg + r.codeNameBase.length();
246: sb.append(remove.substring(0, beg));
247: sb.append(m.codeNameBase);
248: String a = remove.substring(aft);
249: if (m.specVersion != null) {
250: a = a
251: .replaceAll(
252: "<specification-version>[0-9\\.]*</specification-version>",
253: "<specification-version>"
254: + m.specVersion
255: + "</specification-version>");
256: }
257: if (m.releaseVersion == null) {
258: a = a
259: .replaceAll(
260: "<release-version>[0-9]*</release-version>[\n\r ]*",
261: "");
262: }
263:
264: sb.append(a);
265: }
266:
267: sb.append(stream.substring(after));
268:
269: stream = sb.toString();
270: }
271:
272: if (!old.equals(stream)) {
273: FileWriter fw = new FileWriter(file);
274: fw.write(stream);
275: fw.close();
276: return true;
277: } else {
278: return false;
279: }
280: } // end of fix
281:
282: private void simplify(File file, File script,
283: org.apache.tools.ant.taskdefs.Ant task,
284: org.apache.tools.ant.taskdefs.Ant cleanTask)
285: throws IOException, BuildException {
286: if (ant == null || target == null) {
287: return;
288: }
289:
290: int s = (int) file.length();
291: byte[] data = new byte[s];
292: InputStream is = new FileInputStream(file);
293: if (s != is.read(data)) {
294: is.close();
295: throw new BuildException("Cannot read " + file);
296: }
297: is.close();
298:
299: String stream = new String(data);
300: String old = stream;
301:
302: int first = -1;
303: int last = -1;
304: int begin = -1;
305: StringBuffer success = new StringBuffer();
306: StringBuffer sb = new StringBuffer();
307: for (;;) {
308: if (cleanTask != null) {
309: log("Cleaning " + clean + " in " + script,
310: Project.MSG_INFO);
311: cleanTask.execute();
312: }
313:
314: int from = stream.indexOf("<dependency>", begin);
315: if (from == -1) {
316: break;
317: }
318:
319: if (first == -1) {
320: first = from;
321: }
322:
323: int after = stream.indexOf("</dependency>", from);
324: if (after == -1)
325: throw new BuildException(
326: "No </dependency> tag after index " + from);
327: after = findNonSpace(stream, after
328: + "</dependency>".length());
329:
330: last = after;
331: begin = last;
332:
333: // write the file without the
334: FileWriter fw = new FileWriter(file);
335: fw.write(stream.substring(0, from)
336: + stream.substring(after));
337: fw.close();
338:
339: String dep = stream.substring(from, after);
340: if (dep.indexOf("compile-dependency") == -1) {
341: // skip non-compile dependencies
342: sb.append(stream.substring(from, after));
343: continue;
344: }
345:
346: int cnbBeg = dep.indexOf("<code-name-base>");
347: int cnbEnd = dep.indexOf("</code-name-base>");
348: if (cnbBeg != -1 && cnbEnd != -1) {
349: dep = dep.substring(cnbBeg
350: + "<code-name-base>".length(), cnbEnd);
351: }
352:
353: String result;
354: try {
355: log("Executing target " + target + " in " + script,
356: Project.MSG_INFO);
357: task.execute();
358: result = "Ok";
359: success.append(dep);
360: success.append("\n");
361: } catch (BuildException ex) {
362: result = "Failure";
363: // ok, this is needed dependency
364: sb.append(stream.substring(from, after));
365: }
366: log("Removing dependency " + dep + ": " + result,
367: Project.MSG_INFO);
368:
369: }
370:
371: if (first != -1) {
372: // write the file without the
373: FileWriter fw = new FileWriter(file);
374: fw.write(stream.substring(0, first) + sb.toString()
375: + stream.substring(last));
376: fw.close();
377: }
378:
379: log("Final verification runs " + target + " in " + script,
380: Project.MSG_INFO);
381: // now verify, if there is a failure then something is wrong now
382: task.execute();
383:
384: if (success.length() == 0) {
385: log("No dependencies removed from " + script);
386: } else {
387: log("Removed dependencies from " + script + ":\n" + success);
388: }
389: } // end of simplify
390:
391: private static int findNonSpace(String where, int from) {
392: while (from < where.length()
393: && Character.isWhitespace(where.charAt(from))) {
394: from++;
395: }
396: return from;
397: }
398:
399: public static final class Replace extends Object {
400: String codeNameBase;
401: List<Module> modules = new ArrayList<Module>();
402: boolean addCompileTime;
403:
404: public void setCodeNameBase(String s) {
405: codeNameBase = s;
406: }
407:
408: public void setAddCompileTime(boolean b) {
409: addCompileTime = b;
410: }
411:
412: public Module createModule() {
413: Module m = new Module();
414: modules.add(m);
415: return m;
416: }
417:
418: }
419:
420: public static final class Module extends Object {
421: String codeNameBase;
422: String specVersion;
423: String releaseVersion;
424:
425: public void setCodeNameBase(String s) {
426: codeNameBase = s;
427: }
428:
429: public void setSpec(String s) {
430: specVersion = s;
431: }
432:
433: public void setRelease(String r) {
434: releaseVersion = r;
435: }
436: }
437: }
|