blob: 2093d0146508d8ff7a6c443a8c781d0306376a8a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.nbbuild;
import java.io.File;
import java.util.*;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Target;
import org.apache.tools.ant.Task;
/** Pseudo-task to unpack a set of modules.
* Causes the containing target to both depend on the building of the modules in
* the first place; and then to unpack them all to a certain location.
*
* @author various people
*
* 2002-07-31: Rudolf Balada Added build success granularity (Issue 9701),
* fixed modules can't fail, "modules" can fail
*/
public class NbMerge extends Task {
private File dest;
private Vector<String> modules = new Vector<> (); // list of modules defined by build.xml
private Vector<String> buildmodules = new Vector<> (); // list of modules which will be built
private Vector<String> fixedmodules = new Vector<> (); // list of fixed modules defined in build.xml
private Vector<String> buildfixedmodules = new Vector<> (); // List of fixed modules which will be built
private Vector<String> failedmodules = new Vector<> (); // List of failed modules
private Vector<String> builtmodules = new Vector<> (); // list of successfully built modules
private Vector<String> mergemodules = new Vector<> (); // list of successfully built modules
private Vector<String> builttargets = new Vector<> (); // list of successfully built targets
private String targetprefix = "all-";
private List<File> topdirs = new ArrayList<> ();
private List<Suppress> suppress = new LinkedList<> ();
private boolean failonerror = true; // false = enable build success granularity
private boolean mergedependentmodules = false; // merge also dependent modules
private String dummyName;
private Target dummy;
private Hashtable<String,Target> targets;
private String builtmodulesproperty = ""; // if set, update property of the name
// to list of successfuly built modules
/** Target directory to unpack to (top of IDE installation). */
public void setDest (File f) {
dest = f;
}
/** Enable/disable build failing */
public void setFailOnError (boolean b) {
failonerror = b;
}
/** At the end of task, set system property to the list of successfuly
* built modules
*/
public void setBuiltModulesProperty (String s) {
builtmodulesproperty = s;
}
/** Enable/Disable merging also dependencies */
public void setMergeDependentModules (boolean b) {
mergedependentmodules = b;
}
/** Comma-separated list of fixed modules to include. */
public void setFixedModules (String s) {
StringTokenizer tok = new StringTokenizer (s, ", ");
fixedmodules = new Vector<> ();
while (tok.hasMoreTokens ())
fixedmodules.addElement (tok.nextToken ());
}
/** Comma-separated list of modules to include. */
public void setModules (String s) {
StringTokenizer tok = new StringTokenizer (s, ", ");
modules = new Vector<> ();
while (tok.hasMoreTokens ())
modules.addElement (tok.nextToken ());
}
/** String which will have a module name appended to it.
* This will form a target in the same project which should
* create the <samp>netbeans/</samp> subdirectory.
*/
public void setTargetprefix (String s) {
targetprefix = s;
}
/** Set the top directory.
* There should be subdirectories under this for each named module.
*/
public void setTopdir (File t) {
topdirs.add (t);
}
/** Nested topdir addition. */
public class Topdir {
/** Path to an extra topdir. */
public void setPath (File t) {
topdirs.add (t);
}
}
/** Add a nested topdir.
* If there is more than one topdir total, build products
* may be taken from any of them, including from multiple places
* for the same module. (Later topdirs may override build
* products in earlier topdirs.)
*/
public Topdir createTopdir () {
return new Topdir ();
}
/** Locale to suppress. */
public class Suppress {
// [PENDING] also support branding here
String locale;
String iftest;
String unlesstest;
/** Name of the locale, e.g. <samp>ja</samp>. */
public void setLocale (String l) {
locale = l;
}
/** Property which if set will enable the suppression. */
public void setIf (String p) {
iftest = p;
}
/** Property which if set will disable the suppression. */
public void setUnless (String p) {
unlesstest = p;
}
}
/** Add a locale to suppress.
* Files matching this locale suffix will not be merged in.
* E.g. for the locale <samp>ja</samp>, this will exclude
* all files and directories ending in <samp>_ja</samp> as well
* as files ending in <samp>_ja.</samp> plus some extension.
*/
public Suppress createSuppress () {
Suppress s = new Suppress ();
suppress.add (s);
return s;
}
/** Execute targets which cannot fail and though throw BuildException */
private void fixedModulesBuild() throws BuildException {
// Somewhat convoluted code because Project.executeTargets does not
// eliminate duplicates when analyzing dependencies! Ecch.
// build fixed modules first
dummy = new Target ();
dummyName = "nbmerge-" + getOwningTarget().getName();
targets = getProject().getTargets();
while (targets.contains (dummyName))
dummyName += "-x";
dummy.setName (dummyName);
for (String fixedmodule : buildfixedmodules) {
dummy.addDependency (targetprefix + fixedmodule);
}
getProject().addTarget(dummy);
getProject().setProperty("fixedmodules-built", "1" );
@SuppressWarnings("unchecked")
Vector<Target> fullList = getProject().topoSort(dummyName, targets);
// Now remove earlier ones: already done.
Vector<Target> doneList = getProject().topoSort(getOwningTarget().getName(), targets);
List<Target> todo = new ArrayList<>(fullList.subList(0, fullList.indexOf(dummy)));
todo.removeAll(doneList.subList(0, doneList.indexOf(getOwningTarget())));
log("Going to execute targets " + todo);
for (Target nexttargit: todo) {
String targetname = nexttargit.getName();
if ( builttargets.indexOf(targetname) < 0 ) {
// XXX poor replacement for Project.fireTargetStarted etc.
System.out.println(""); System.out.println(targetname + ":");
try {
nexttargit.execute();
} catch (BuildException ex) {
log("Failed to build target: " + targetname, Project.MSG_ERR);
throw ex;
}
builttargets.addElement(targetname);
}
}
builtmodules.addAll(buildfixedmodules); // add already built fixed modules to the list
log("fixedmodules=" + buildfixedmodules, Project.MSG_DEBUG);
log("builtmodules=" + builtmodules, Project.MSG_VERBOSE);
}
/** Execute targets which can fail _without_ throwing BuildException */
private void modulesBuild() throws BuildException {
if ( ! failonerror ) {
// build the rest of modules
for (String module : buildmodules) {
dummy = new Target ();
dummyName = "nbmerge-" + getOwningTarget().getName() + "-" + module;
while (targets.contains (dummyName))
dummyName += "-x";
dummy.setName (dummyName);
dummy.addDependency (targetprefix + module);
getProject().addTarget(dummy);
@SuppressWarnings("unchecked")
Vector<Target> fullList = getProject().topoSort(dummyName, targets);
// Now remove earlier ones: already done.
@SuppressWarnings("unchecked")
Vector<Target> doneList = getProject().topoSort(getOwningTarget().getName(), targets);
List<Target> todo = new ArrayList<>(fullList.subList(0, fullList.indexOf(dummy)));
todo.removeAll(doneList.subList(0, doneList.indexOf(getOwningTarget())));
Iterator<Target> targit = todo.iterator();
try {
while (targit.hasNext()) {
Target nexttargit = targit.next();
String targetname = nexttargit.getName();
if ( builttargets.indexOf(targetname) < 0 ) {
System.out.println(); System.out.println(targetname + ":");
nexttargit.execute();
builttargets.addElement(targetname);
}
}
builtmodules.addElement(module);
} catch (BuildException BE) {
log(BE.toString(), Project.MSG_WARN);
BE.printStackTrace();
failedmodules.addElement(module);
}
}
log("builtmodules=" + builtmodules, Project.MSG_VERBOSE);
log("failedmodules=" + failedmodules, Project.MSG_VERBOSE);
}
}
public void execute () throws BuildException {
if (topdirs.isEmpty ()) {
throw new BuildException("You must set at least one topdir attribute", getLocation());
}
buildfixedmodules.addAll(fixedmodules);
buildmodules.addAll(modules);
if (( modules.size() > 0 ) && ( fixedmodules.size() == 0 ) && (! failonerror)) {
log("Unable to build without fixedmodules set", Project.MSG_WARN);
log("Swapping modules list with fixedmodules list", Project.MSG_WARN);
buildfixedmodules.addAll(modules);
buildmodules.removeAllElements();
}
if (( failonerror ) && ( modules.size() > 0 )) {
// failonerror is enabled => build success granularity is disabled
// though move all modules to fixedmodules
buildfixedmodules.addAll(modules);
buildmodules.removeAllElements();
}
// build of fixed modules
fixedModulesBuild();
// build of the rest of modules
modulesBuild();
// final data merging
dataMerge();
// display build success status
if (builtmodules.size() > 0 ) {
log("builtmodules=" + builtmodules);
log("builttargets=" + builttargets);
if (failedmodules.size() > 0 ) {
log("SOME MODULES FAILED TO BUILD, BUT THEIR BuildException WAS CAUGHT.", Project.MSG_WARN);
log("failedmodules=" + failedmodules, Project.MSG_WARN);
}
if ( mergemodules.size() > 0 ) {
if ( builtmodulesproperty.length() > 0 ) {
Vector<String> setmodules = new Vector<>();
// add all successfuly built modules
setmodules.addAll(mergemodules);
// remove all fixed modules (don't put fixed modules to modules list)
setmodules.removeAll(fixedmodules);
// check if the modules list is equal to mergemodules without fixedmodules
if (( ! modules.containsAll(setmodules)) || ( ! setmodules.containsAll(modules))) {
String bm = setmodules.toString();
bm = bm.substring( 1, bm.length() - 1);
if (bm.length() > 0 ) {
log("Setting property \"" + builtmodulesproperty + "\" to new value " + bm); //, Project.MSG_VERBOSE);
getProject().setUserProperty(builtmodulesproperty, bm);
}
}
}
}
} else {
throw new BuildException("No modules were built", getLocation());
}
}
/** Do final data merge */
private void dataMerge() throws BuildException {
List<String> suppressedlocales = new LinkedList<> ();
for (Suppress s: suppress) {
if (s.iftest != null && getProject().getProperty(s.iftest) == null) {
continue;
} else if (s.unlesstest != null && getProject().getProperty(s.unlesstest) != null) {
continue;
}
log ("Suppressing locale: " + s.locale);
suppressedlocales.add (s.locale);
}
UpdateTracking tr = new UpdateTracking( dest.getAbsolutePath() );
log ( dest.getAbsolutePath() );
for(String locale: suppressedlocales) {
tr.removeLocalized(locale);
}
}
}