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.util.*;
046:
047: import org.apache.tools.ant.BuildException;
048: import org.apache.tools.ant.Project;
049: import org.apache.tools.ant.Target;
050: import org.apache.tools.ant.Task;
051:
052: /** Pseudo-task to unpack a set of modules.
053: * Causes the containing target to both depend on the building of the modules in
054: * the first place; and then to unpack them all to a certain location.
055: *
056: * @author various people
057: *
058: * 2002-07-31: Rudolf Balada Added build success granularity (Issue 9701),
059: * fixed modules can't fail, "modules" can fail
060: */
061: public class NbMerge extends Task {
062:
063: private File dest;
064: private Vector<String> modules = new Vector<String>(); // list of modules defined by build.xml
065: private Vector<String> buildmodules = new Vector<String>(); // list of modules which will be built
066: private Vector<String> fixedmodules = new Vector<String>(); // list of fixed modules defined in build.xml
067: private Vector<String> buildfixedmodules = new Vector<String>(); // List of fixed modules which will be built
068: private Vector<String> failedmodules = new Vector<String>(); // List of failed modules
069: private Vector<String> builtmodules = new Vector<String>(); // list of successfully built modules
070: private Vector<String> mergemodules = new Vector<String>(); // list of successfully built modules
071: private Vector<String> builttargets = new Vector<String>(); // list of successfully built targets
072: private String targetprefix = "all-";
073: private List<File> topdirs = new ArrayList<File>();
074: private List<Suppress> suppress = new LinkedList<Suppress>();
075: private boolean failonerror = true; // false = enable build success granularity
076: private boolean mergedependentmodules = false; // merge also dependent modules
077: private String dummyName;
078: private Target dummy;
079: private Hashtable targets;
080: private String builtmodulesproperty = ""; // if set, update property of the name
081:
082: // to list of successfuly built modules
083:
084: /** Target directory to unpack to (top of IDE installation). */
085: public void setDest(File f) {
086: dest = f;
087: }
088:
089: /** Enable/disable build failing */
090: public void setFailOnError(boolean b) {
091: failonerror = b;
092: }
093:
094: /** At the end of task, set system property to the list of successfuly
095: * built modules
096: */
097: public void setBuiltModulesProperty(String s) {
098: builtmodulesproperty = s;
099: }
100:
101: /** Enable/Disable merging also dependencies */
102: public void setMergeDependentModules(boolean b) {
103: mergedependentmodules = b;
104: }
105:
106: /** Comma-separated list of fixed modules to include. */
107: public void setFixedModules(String s) {
108: StringTokenizer tok = new StringTokenizer(s, ", ");
109: fixedmodules = new Vector<String>();
110: while (tok.hasMoreTokens())
111: fixedmodules.addElement(tok.nextToken());
112: }
113:
114: /** Comma-separated list of modules to include. */
115: public void setModules(String s) {
116: StringTokenizer tok = new StringTokenizer(s, ", ");
117: modules = new Vector<String>();
118: while (tok.hasMoreTokens())
119: modules.addElement(tok.nextToken());
120: }
121:
122: /** String which will have a module name appended to it.
123: * This will form a target in the same project which should
124: * create the <samp>netbeans/</samp> subdirectory.
125: */
126: public void setTargetprefix(String s) {
127: targetprefix = s;
128: }
129:
130: /** Set the top directory.
131: * There should be subdirectories under this for each named module.
132: */
133: public void setTopdir(File t) {
134: topdirs.add(t);
135: }
136:
137: /** Nested topdir addition. */
138: public class Topdir {
139: /** Path to an extra topdir. */
140: public void setPath(File t) {
141: topdirs.add(t);
142: }
143: }
144:
145: /** Add a nested topdir.
146: * If there is more than one topdir total, build products
147: * may be taken from any of them, including from multiple places
148: * for the same module. (Later topdirs may override build
149: * products in earlier topdirs.)
150: */
151: public Topdir createTopdir() {
152: return new Topdir();
153: }
154:
155: /** Locale to suppress. */
156: public class Suppress {
157: // [PENDING] also support branding here
158: String locale;
159: String iftest;
160: String unlesstest;
161:
162: /** Name of the locale, e.g. <samp>ja</samp>. */
163: public void setLocale(String l) {
164: locale = l;
165: }
166:
167: /** Property which if set will enable the suppression. */
168: public void setIf(String p) {
169: iftest = p;
170: }
171:
172: /** Property which if set will disable the suppression. */
173: public void setUnless(String p) {
174: unlesstest = p;
175: }
176: }
177:
178: /** Add a locale to suppress.
179: * Files matching this locale suffix will not be merged in.
180: * E.g. for the locale <samp>ja</samp>, this will exclude
181: * all files and directories ending in <samp>_ja</samp> as well
182: * as files ending in <samp>_ja.</samp> plus some extension.
183: */
184: public Suppress createSuppress() {
185: Suppress s = new Suppress();
186: suppress.add(s);
187: return s;
188: }
189:
190: /** Execute targets which cannot fail and though throw BuildException */
191: private void fixedModulesBuild() throws BuildException {
192: // Somewhat convoluted code because Project.executeTargets does not
193: // eliminate duplicates when analyzing dependencies! Ecch.
194: // build fixed modules first
195: dummy = new Target();
196: dummyName = "nbmerge-" + getOwningTarget().getName();
197: targets = getProject().getTargets();
198: while (targets.contains(dummyName))
199: dummyName += "-x";
200: dummy.setName(dummyName);
201: for (String fixedmodule : buildfixedmodules) {
202: dummy.addDependency(targetprefix + fixedmodule);
203: }
204: getProject().addTarget(dummy);
205:
206: getProject().setProperty("fixedmodules-built", "1");
207: @SuppressWarnings("unchecked")
208: Vector<Target> fullList = getProject().topoSort(dummyName,
209: targets);
210: // Now remove earlier ones: already done.
211: Vector doneList = getProject().topoSort(
212: getOwningTarget().getName(), targets);
213: List<Target> todo = new ArrayList<Target>(fullList.subList(0,
214: fullList.indexOf(dummy)));
215: todo.removeAll(doneList.subList(0, doneList
216: .indexOf(getOwningTarget())));
217: log("Going to execute targets " + todo);
218: for (Target nexttargit : todo) {
219: String targetname = nexttargit.getName();
220: if (builttargets.indexOf(targetname) < 0) {
221: // XXX poor replacement for Project.fireTargetStarted etc.
222: System.out.println("");
223: System.out.println(targetname + ":");
224: try {
225: nexttargit.execute();
226: } catch (BuildException ex) {
227: log("Failed to build target: " + targetname,
228: Project.MSG_ERR);
229: throw ex;
230: }
231: builttargets.addElement(targetname);
232: }
233: }
234:
235: builtmodules.addAll(buildfixedmodules); // add already built fixed modules to the list
236: log("fixedmodules=" + buildfixedmodules, Project.MSG_DEBUG);
237: log("builtmodules=" + builtmodules, Project.MSG_VERBOSE);
238: }
239:
240: /** Execute targets which can fail _without_ throwing BuildException */
241: private void modulesBuild() throws BuildException {
242: if (!failonerror) {
243: // build the rest of modules
244: for (String module : buildmodules) {
245: dummy = new Target();
246: dummyName = "nbmerge-" + getOwningTarget().getName()
247: + "-" + module;
248: while (targets.contains(dummyName))
249: dummyName += "-x";
250: dummy.setName(dummyName);
251: dummy.addDependency(targetprefix + module);
252: getProject().addTarget(dummy);
253: @SuppressWarnings("unchecked")
254: Vector<Target> fullList = getProject().topoSort(
255: dummyName, targets);
256: // Now remove earlier ones: already done.
257: @SuppressWarnings("unchecked")
258: Vector<Target> doneList = getProject().topoSort(
259: getOwningTarget().getName(), targets);
260: List<Target> todo = new ArrayList<Target>(fullList
261: .subList(0, fullList.indexOf(dummy)));
262: todo.removeAll(doneList.subList(0, doneList
263: .indexOf(getOwningTarget())));
264:
265: Iterator<Target> targit = todo.iterator();
266: try {
267: while (targit.hasNext()) {
268: Target nexttargit = targit.next();
269: String targetname = nexttargit.getName();
270: if (builttargets.indexOf(targetname) < 0) {
271: System.out.println();
272: System.out.println(targetname + ":");
273: nexttargit.execute();
274: builttargets.addElement(targetname);
275: }
276:
277: }
278: builtmodules.addElement(module);
279: } catch (BuildException BE) {
280: log(BE.toString(), Project.MSG_WARN);
281: BE.printStackTrace();
282: failedmodules.addElement(module);
283: }
284: }
285: log("builtmodules=" + builtmodules, Project.MSG_VERBOSE);
286: log("failedmodules=" + failedmodules, Project.MSG_VERBOSE);
287: }
288: }
289:
290: public void execute() throws BuildException {
291: if (topdirs.isEmpty()) {
292: throw new BuildException(
293: "You must set at least one topdir attribute",
294: getLocation());
295: }
296:
297: buildfixedmodules.addAll(fixedmodules);
298: buildmodules.addAll(modules);
299:
300: if ((modules.size() > 0) && (fixedmodules.size() == 0)
301: && (!failonerror)) {
302: log("Unable to build without fixedmodules set",
303: Project.MSG_WARN);
304: log("Swapping modules list with fixedmodules list",
305: Project.MSG_WARN);
306: buildfixedmodules.addAll(modules);
307: buildmodules.removeAllElements();
308: }
309:
310: if ((failonerror) && (modules.size() > 0)) {
311: // failonerror is enabled => build success granularity is disabled
312: // though move all modules to fixedmodules
313: buildfixedmodules.addAll(modules);
314: buildmodules.removeAllElements();
315: }
316:
317: // build of fixed modules
318: fixedModulesBuild();
319:
320: // build of the rest of modules
321: modulesBuild();
322:
323: // final data merging
324: dataMerge();
325:
326: // display build success status
327: if (builtmodules.size() > 0) {
328: log("builtmodules=" + builtmodules);
329: log("builttargets=" + builttargets);
330: if (failedmodules.size() > 0) {
331: log(
332: "SOME MODULES FAILED TO BUILD, BUT THEIR BuildException WAS CAUGHT.",
333: Project.MSG_WARN);
334: log("failedmodules=" + failedmodules, Project.MSG_WARN);
335: }
336:
337: if (mergemodules.size() > 0) {
338: if (builtmodulesproperty.length() > 0) {
339: Vector<String> setmodules = new Vector<String>();
340: // add all successfuly built modules
341: setmodules.addAll(mergemodules);
342: // remove all fixed modules (don't put fixed modules to modules list)
343: setmodules.removeAll(fixedmodules);
344: // check if the modules list is equal to mergemodules without fixedmodules
345: if ((!modules.containsAll(setmodules))
346: || (!setmodules.containsAll(modules))) {
347: String bm = setmodules.toString();
348: bm = bm.substring(1, bm.length() - 1);
349: if (bm.length() > 0) {
350: log("Setting property \""
351: + builtmodulesproperty
352: + "\" to new value " + bm); //, Project.MSG_VERBOSE);
353: getProject().setUserProperty(
354: builtmodulesproperty, bm);
355: }
356: }
357: }
358: }
359:
360: } else {
361: throw new BuildException("No modules were built",
362: getLocation());
363: }
364:
365: }
366:
367: /** Do final data merge */
368: private void dataMerge() throws BuildException {
369: List<String> suppressedlocales = new LinkedList<String>();
370: Iterator it = suppress.iterator();
371: while (it.hasNext()) {
372: Suppress s = (Suppress) it.next();
373: if (s.iftest != null
374: && getProject().getProperty(s.iftest) == null) {
375: continue;
376: } else if (s.unlesstest != null
377: && getProject().getProperty(s.unlesstest) != null) {
378: continue;
379: }
380: log("Suppressing locale: " + s.locale);
381: suppressedlocales.add(s.locale);
382: }
383:
384: UpdateTracking tr = new UpdateTracking(dest.getAbsolutePath());
385: log(dest.getAbsolutePath());
386: while (it.hasNext()) {
387: String locale = (String) it.next();
388: tr.removeLocalized(locale);
389: }
390: }
391: }
|