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.FileOutputStream;
046: import java.io.FileWriter;
047: import java.io.IOException;
048: import java.io.OutputStream;
049: import java.io.PrintWriter;
050: import java.io.Writer;
051: import java.util.ArrayList;
052: import java.util.Collections;
053: import java.util.HashSet;
054: import java.util.List;
055: import java.util.Map;
056: import java.util.Set;
057: import java.util.StringTokenizer;
058: import java.util.TreeMap;
059: import java.util.TreeSet;
060: import org.apache.tools.ant.BuildException;
061: import org.apache.tools.ant.Project;
062: import org.apache.tools.ant.Task;
063: import org.w3c.dom.Document;
064: import org.w3c.dom.Element;
065: import org.w3c.dom.NodeList;
066: import org.xml.sax.InputSource;
067: import org.xml.sax.SAXException;
068:
069: /**
070: * Analyzes build.properties and cluster.properties and tries to diagnose any problems.
071: * Also produces a summary of moduleconfig contents which is written to a golden file.
072: * @author Jesse Glick
073: */
074: public final class CheckModuleConfigs extends Task {
075:
076: private File nbroot;
077:
078: public CheckModuleConfigs() {
079: }
080:
081: public void setNbroot(File f) {
082: nbroot = f;
083: }
084:
085: public @Override
086: void execute() throws BuildException {
087: if (nbroot == null) {
088: throw new BuildException("Must define 'nbroot' param",
089: getLocation());
090: }
091: File buildPropertiesFile = new File(nbroot, "nbbuild"
092: + File.separatorChar + "build.properties");
093: File clusterPropertiesFile = new File(nbroot, "nbbuild"
094: + File.separatorChar + "cluster.properties");
095: File goldenFile = new File(nbroot, "nbbuild"
096: + File.separatorChar + "build" + File.separatorChar
097: + "generated" + File.separatorChar
098: + "moduleconfigs.txt");
099: File masterProjectXml = new File(nbroot, "ide"
100: + File.separatorChar + "allmodules"
101: + File.separatorChar + "nbproject" + File.separatorChar
102: + "project.xml");
103: @SuppressWarnings("unchecked")
104: Map<String, String> properties = getProject().getProperties();
105: Map<String, Set<String>> configs = loadModuleConfigs(
106: properties, buildPropertiesFile);
107: Map<String, Set<String>> clusters = loadModuleClusters(
108: properties, clusterPropertiesFile);
109: Set<String> allClusterModules = new TreeSet<String>();
110: for (Set<String> s : clusters.values()) {
111: allClusterModules.addAll(s);
112: }
113: try {
114: writeModuleConfigs(goldenFile, configs, buildPropertiesFile);
115: } catch (IOException e) {
116: throw new BuildException(
117: "Could not write to " + goldenFile, e,
118: getLocation());
119: }
120: try {
121: writeMasterProjectXml(masterProjectXml, allClusterModules);
122: } catch (SAXException e) {
123: throw new BuildException("Could not write to "
124: + masterProjectXml, e, getLocation());
125: } catch (IOException e) {
126: throw new BuildException("Could not write to "
127: + masterProjectXml, e, getLocation());
128: }
129: Set<String> s;
130: /* Apparently wanted now?
131: // Check that stable != daily-alpha-nbms:
132: s = new TreeSet((Set) configs.get("stable"));
133: s.retainAll((Set) configs.get("daily-alpha-nbms"));
134: if (!s.isEmpty()) {
135: log(buildPropertiesFile + ": warning: stable and daily-alpha-nbms configs overlap: " + s);
136: }
137: */
138: /* This is not actually desired; just includes everything:
139: // Check that sigtest <= javadoc:
140: s = new TreeSet((Set) configs.get("sigtest"));
141: s.removeAll((Set) configs.get("javadoc"));
142: if (!s.isEmpty()) {
143: log(buildPropertiesFile + ": warning: sigtest config contains entries not in javadoc config: " + s);
144: }
145: */
146: /* This config is no more?
147: // Check that platform-javadoc <= javadoc:
148: s = new TreeSet((Set) configs.get("platform-javadoc"));
149: s.removeAll((Set) configs.get("javadoc"));
150: if (!s.isEmpty()) {
151: log(buildPropertiesFile + ": warning: platform-javadoc config contains entries not in javadoc config: " + s);
152: }
153: */
154: // Check that javadoc <= stable + daily-alpha-nbms:
155: s = new TreeSet<String>(configs.get("javadoc"));
156: s.removeAll(configs.get("stable"));
157: s.removeAll(configs.get("daily-alpha-nbms"));
158: if (!s.isEmpty()) {
159: log(buildPropertiesFile
160: + ": warning: javadoc config contains entries not in stable and daily-alpha-nbms configs: "
161: + s);
162: }
163: /*
164: // Check that platform-javadoc = javadoc where module in platform cluster:
165: Set/ *<String>* / platformJavadoc = (Set) configs.get("platform-javadoc");
166: Set/ *<String>* / platformClusterJavadoc = (Set) configs.get("javadoc");
167: platformClusterJavadoc.retainAll((Set) clusters.get("nb.cluster.platform"));
168: s = new TreeSet(platformJavadoc);
169: s.removeAll(platformClusterJavadoc);
170: if (!s.isEmpty()) {
171: log(buildPropertiesFile + ": warning: platform-javadoc config not equal to javadoc config for platform cluster modules: " + s);
172: }
173: s = new TreeSet(platformClusterJavadoc);
174: s.removeAll(platformJavadoc);
175: if (!s.isEmpty()) {
176: log(buildPropertiesFile + ": warning: platform-javadoc config not equal to javadoc config restricted to platform cluster modules: " + s);
177: }
178: */
179: // Check that stable = modules in enumerated clusters:
180: Set<String> stable = configs.get("all");
181: s = new TreeSet<String>(stable);
182: s.removeAll(allClusterModules);
183: if (!s.isEmpty()) {
184: log(buildPropertiesFile
185: + ": warning: 'all' config not equal to listed cluster modules: "
186: + s);
187: }
188: s = new TreeSet<String>(allClusterModules);
189: s.removeAll(stable);
190: if (!s.isEmpty()) {
191: log(buildPropertiesFile
192: + ": warning: 'all' config not equal to listed cluster modules: "
193: + s);
194: }
195: // Check that platform = modules in platform cluster:
196: Set<String> platform = configs.get("platform");
197: Set<String> platformCluster = clusters
198: .get("nb.cluster.platform");
199: s = new TreeSet<String>(platform);
200: s.removeAll(platformCluster);
201: if (!s.isEmpty()) {
202: log(buildPropertiesFile
203: + ": warning: platform config not equal to platform cluster modules: "
204: + s);
205: }
206: s = new TreeSet<String>(platformCluster);
207: s.removeAll(platform);
208: if (!s.isEmpty()) {
209: log(buildPropertiesFile
210: + ": warning: platform config not equal to platform cluster modules: "
211: + s);
212: }
213: }
214:
215: @SuppressWarnings("unchecked")
216: private Set<String> split(String list, boolean warnIfUnsorted) {
217: List elements = Collections
218: .list(new StringTokenizer(list, ", "));
219: if (warnIfUnsorted) {
220: List sorted = new ArrayList(elements);
221: Collections.sort(sorted);
222: if (!sorted.equals(elements)) {
223: log("warning: unsorted list: " + elements);
224: }
225: }
226: return new HashSet(elements);
227: }
228:
229: private Map<String, Set<String>> loadModuleConfigs(
230: Map<String, String> buildProperties,
231: File buildPropertiesFile) {
232: Map<String, Set<String>> configs = new TreeMap<String, Set<String>>();
233: for (String k : buildProperties.keySet()) {
234: String prefix = "config.modules.";
235: if (!k.startsWith(prefix)) {
236: continue;
237: }
238: String config = k.substring(prefix.length());
239: Set<String> modules = new TreeSet<String>(split(
240: buildProperties.get(k), false));
241: String fixedK = "config.fixedmodules." + config;
242: String fixed = buildProperties.get(fixedK);
243: if (fixed != null) {
244: modules.addAll(split(fixed, false));
245: } else {
246: log(buildPropertiesFile + ": warning: have " + k
247: + " but no " + fixedK, Project.MSG_WARN);
248: }
249: configs.put(config, modules);
250: }
251: return configs;
252: }
253:
254: private void writeModuleConfigs(File goldenFile,
255: Map<String, Set<String>> configs, File buildPropertiesFile)
256: throws IOException {
257: log("Writing moduleconfigs " + configs.keySet() + " from "
258: + buildPropertiesFile + " to " + goldenFile);
259: goldenFile.getParentFile().mkdirs();
260: Writer w = new FileWriter(goldenFile); // default encoding OK
261: try {
262: PrintWriter pw = new PrintWriter(w);
263: pw
264: .println("# To update, run: ant -f nbbuild/build.xml check-module-configs");
265: for (Map.Entry<String, Set<String>> entry : configs
266: .entrySet()) {
267: String config = entry.getKey();
268: for (String module : entry.getValue()) {
269: pw.println(config + ':' + module);
270: }
271: }
272: pw.flush();
273: } finally {
274: w.close();
275: }
276: }
277:
278: private Map<String, Set<String>> loadModuleClusters(
279: Map<String, String> clusterProperties,
280: File clusterPropertiesFile) {
281: String l = clusterProperties.get("clusters.config.full.list");
282: if (l == null) {
283: log(
284: clusterPropertiesFile
285: + ": warning: no definition for clusters.config.full.list",
286: Project.MSG_WARN);
287: return Collections.emptyMap();
288: }
289: Map<String, Set<String>> clusters = new TreeMap<String, Set<String>>();
290: for (String cluster : split(l, false)) {
291: l = clusterProperties.get(cluster);
292: if (l == null) {
293: log(clusterPropertiesFile
294: + ": warning: no definition for " + cluster,
295: Project.MSG_WARN);
296: continue;
297: }
298: clusters.put(cluster, new TreeSet<String>(split(l, true)));
299: }
300: return clusters;
301: }
302:
303: private void writeMasterProjectXml(File masterProjectXml,
304: Set<String> allClusterModules) throws IOException,
305: SAXException {
306: log("Writing module list to " + masterProjectXml);
307: Document doc = XMLUtil.parse(new InputSource(masterProjectXml
308: .toURI().toString()), false, true, null, null);
309: NodeList nl = doc.getElementsByTagName("subprojects");
310: if (nl.getLength() != 1) {
311: throw new IOException("No or multiple <subprojects>");
312: }
313: Element sp = (Element) nl.item(0);
314: nl = sp.getChildNodes();
315: while (nl.getLength() > 0) {
316: sp.removeChild(nl.item(0));
317: }
318: sp
319: .appendChild(doc
320: .createComment(" To update, run: ant -f nbbuild/build.xml check-module-configs "));
321: for (String module : allClusterModules) {
322: if (new File(nbroot, (module + "/nbproject/project.xml")
323: .replace('/', File.separatorChar)).isFile()) {
324: Element e = doc
325: .createElementNS(
326: "http://www.netbeans.org/ns/freeform-project/1",
327: "project");
328: String path = "../../" + module;
329: e.appendChild(doc.createTextNode(path.replaceFirst(
330: "^\\.\\./\\.\\./ide/", "../")));
331: sp.appendChild(e);
332: } else {
333: sp.appendChild(doc.createComment(" Unprojectized: "
334: + module + " "));
335: }
336: }
337: OutputStream os = new FileOutputStream(masterProjectXml);
338: try {
339: XMLUtil.write(doc, os);
340: } finally {
341: os.close();
342: }
343: }
344:
345: }
|