sdk/build-tools/org/opends/build/tools/CheckPrecommit.java
New file @@ -0,0 +1,402 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2008 Sun Microsystems, Inc. */ package org.opends.build.tools; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.GregorianCalendar; import java.util.HashSet; import java.util.LinkedList; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.FileSet; import org.tmatesoft.svn.core.SVNDepth; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.wc.SVNPropertyData; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc.ISVNStatusHandler; import org.tmatesoft.svn.core.wc.SVNClientManager; import org.tmatesoft.svn.core.wc.SVNStatus; import org.tmatesoft.svn.core.wc.SVNWCClient; /** * This class provides an implementation of an Ant task that may be used to * perform various checks to deteermine whether a file is suitable to be * committed. This includes: * <UL> * <LI>Make sure that the file has the correct "svn:eol-style" property * value.</LI> * <LI>If a file contains a line that appears to be a comment and includes the * word "copyright", then it should contain the current year.</LI> * </UL> */ public class CheckPrecommit extends Task implements ISVNStatusHandler { /** * The name of the system property that may be used to prevent copyright date * problems from failing the build. */ public static final String IGNORE_COPYRIGHT_ERRORS_PROPERTY = "org.opends.server.IgnoreCopyrightDateErrors"; /** * The name of the system property that may be used to prevent svn eol-style * problems from failing the build. */ public static final String IGNORE_EOLSTYLE_ERRORS_PROPERTY = "org.opends.server.IgnoreEOLStyleErrors"; /** * */ public static final HashSet<String> CHECKED_EXTENSIONS = new HashSet<String>(); static { CHECKED_EXTENSIONS.add("java"); CHECKED_EXTENSIONS.add("xml"); CHECKED_EXTENSIONS.add("xsd"); CHECKED_EXTENSIONS.add("xsl"); CHECKED_EXTENSIONS.add("html"); CHECKED_EXTENSIONS.add("sh"); CHECKED_EXTENSIONS.add("bat"); CHECKED_EXTENSIONS.add("ldif"); CHECKED_EXTENSIONS.add("txt"); CHECKED_EXTENSIONS.add("c"); CHECKED_EXTENSIONS.add("h"); CHECKED_EXTENSIONS.add("mc"); CHECKED_EXTENSIONS.add("Makefile"); } // The path to the directory that is the base of the workspace. private File workspacePath; // The set of files that appear to have problems with the EOL style. private LinkedList<String> eolStyleProblemFiles = new LinkedList<String>(); // The set of files that appear to have problems with the copyright date. private LinkedList<String> copyrightProblemFiles = new LinkedList<String>(); // The path to the root of the Subversion workspace to check. private String workspace = null; // The string representation of the current year. private String yearString; // The overall SVN Client Manager. required with svnkit 1.2.x private static SVNClientManager ourClientManager = SVNClientManager.newInstance(); // The property client used to look at file properties. private SVNWCClient propertyClient; /** * Specifies the path to the root of the Subversion workspace for which to * retrieve the revision number. * * @param workspace The path to the root of the Subversion workspace for * which to retrieve the revision number. */ public void setWorkspace(String workspace) { this.workspace = workspace; } /** * Performs the appropriate processing needed for this task. In this case, * it uses SVNKit to identify all modified files in the current workspace. * For all source files, look for comment lines containing the word * "copyright" and make sure at least one of them contains the current year. */ @Override() public void execute() { if ((workspace == null) || (workspace.length() == 0)) { workspacePath = getProject().getBaseDir(); } else { workspacePath = new File(workspace); } // Get the year to use in the determination. GregorianCalendar calendar = new GregorianCalendar(); int year = calendar.get(GregorianCalendar.YEAR); yearString = String.valueOf(year); // Process the base directory and all of its subdirectories. propertyClient = ourClientManager.getWCClient(); try { long status = ourClientManager.getStatusClient().doStatus(workspacePath, SVNRevision.WORKING, SVNDepth.INFINITY, false, false, false, false, this, null); } catch (Exception e) { e.printStackTrace(); System.err.println("WARNING: Encountered an error while examining " + "Subversion status: " + e); System.err.println("No further checks will be performed."); return; } boolean fail = false; if (! eolStyleProblemFiles.isEmpty()) { System.err.println("WARNING: Potential svn:eol-style updates needed " + "for the following files:"); for (String filename : eolStyleProblemFiles) { System.err.println(" " + filename); } String ignoreProp = getProject().getProperty(IGNORE_EOLSTYLE_ERRORS_PROPERTY); if ((ignoreProp == null) || (! ignoreProp.equalsIgnoreCase("true"))) { fail = true; System.err.println("Fix svn:eol-style problems before proceeding, or " + "use '-D" + IGNORE_EOLSTYLE_ERRORS_PROPERTY + "=true' to ignore svn eol-style warnings."); } } if (! copyrightProblemFiles.isEmpty()) { System.err.println("WARNING: Potential copyright year updates needed " + "for the following files:"); for (String filename : copyrightProblemFiles) { System.err.println(" " + filename); } String ignoreProp = getProject().getProperty(IGNORE_COPYRIGHT_ERRORS_PROPERTY); if ((ignoreProp == null) || (! ignoreProp.equalsIgnoreCase("true"))) { fail = true; System.err.println("Fix copyright date problems before proceeding, " + "or use '-D" + IGNORE_COPYRIGHT_ERRORS_PROPERTY + "=true' to ignore copyright warnings."); } } if (fail) { throw new BuildException(); } } /** * Examines the provided status item to determine whether the associated file * is acceptable. * * @param status The SVN status information for the file of interest. */ public void handleStatus(SVNStatus status) { File file = status.getFile(); if ((! file.exists()) || (! file.isFile())) { // The file doesn't exist (which probably means it's been deleted) or // isn't a regular file, so we'll ignore it. return; } String fileName = file.getName(); int lastPeriodPos = fileName.lastIndexOf('.'); if (lastPeriodPos > 0) { String extension = fileName.substring(lastPeriodPos+1); if (! CHECKED_EXTENSIONS.contains(extension.toLowerCase())) { // The file doesn't have an extension that we care about, so skip it. return; } } else { // The file doesn't have an extension. We'll still want to check it if // it's in a resource/bin directory. File parentDirectory = file.getParentFile(); if ((parentDirectory == null) || (! parentDirectory.getName().equals("bin"))) { return; } parentDirectory = parentDirectory.getParentFile(); if ((parentDirectory == null) || (! parentDirectory.getName().equals("resource"))) { return; } } String filePath = file.getAbsolutePath(); if (filePath.startsWith(workspacePath.getPath() + "/")) { filePath = filePath.substring(workspacePath.getPath().length() + 1); } // Check to make sure that the file has the correct EOL style. try { SVNPropertyData propertyData = propertyClient.doGetProperty(file, "svn:eol-style", SVNRevision.BASE, SVNRevision.WORKING); if ((propertyData == null) || (! propertyData.getValue().getString().equals("native"))) { eolStyleProblemFiles.add(filePath); } } catch (SVNException se) { // This could happen if the file isn't under version control. If so, then // we can't check the eol-style but we should at least be able to check // the copyright dates, so keep going. } // Check to see whether the file has a comment line containing a copyright // without the current year. BufferedReader reader = null; try { boolean copyrightFound = false; boolean correctYearFound = false; reader = new BufferedReader(new FileReader(file)); String line = reader.readLine(); while (line != null) { String lowerLine = line.toLowerCase().trim(); if (isCommentLine(lowerLine)) { int copyrightPos = lowerLine.indexOf("copyright"); if (copyrightPos > 0) { copyrightFound = true; if (lowerLine.indexOf(yearString) > 0) { correctYearFound = true; break; } } } line = reader.readLine(); } if (copyrightFound && (! correctYearFound)) { copyrightProblemFiles.add(filePath); } } catch (IOException ioe) { System.err.println("ERROR: Could not read file " + filePath + " to check copyright date."); System.err.println("No further copyright date checking will be " + "performed."); throw new RuntimeException(); } finally { try { if (reader != null) { reader.close(); } } catch (Exception e) {} } } /** * Indicates whether the provided line appears to be a comment line. It will * check for a number of common comment indicators in Java source files, * shell scripts, XML files, and LDIF files. * * @param lowerLine The line to be checked. It should have been coverted to * all lowercase characters and any leading spaces * removed. * * @return {@code true} if it appears that the line is a comment line, or * {@code false} if not. */ private static boolean isCommentLine(String lowerLine) { if (lowerLine.startsWith("/*") || lowerLine.startsWith("*") || lowerLine.startsWith("//") || lowerLine.startsWith("#") || lowerLine.startsWith("rem") || lowerLine.startsWith("<!--") || lowerLine.startsWith("!")) { return true; } else { return false; } } } sdk/build-tools/org/opends/build/tools/ConcatSchema.java
New file @@ -0,0 +1,272 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2008 Sun Microsystems, Inc. */ package org.opends.build.tools; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.util.LinkedList; import java.util.TreeSet; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task; /** * This class provides an implementation of an Ant task that concatenates the * contents of the files in the schema directory to create a base schema that * may be used during the upgrade process. Each element will also include the * X-SCHEMA-FILE extension to indicate the source schema file. */ public class ConcatSchema extends Task { // The path to the directory containing the schema files. private String schemaDirectory; // The path to the concatenated schema file to create. private String toFile; /** * Specifies the path to the directory containing the schema files. * * @param schemaDirectory The path to the directory containing the schema * files. */ public void setSchemaDirectory(String schemaDirectory) { this.schemaDirectory = schemaDirectory; } /** * Specifies the path to the file to create containing the concatenated schema * elements. * * @param toFile The path to the file containing the concatenated schema * elements. */ public void setToFile(String toFile) { this.toFile = toFile; } /** * Performs the appropriate processing needed for this task. In this case, * it uses SVNKit to identify all modified files in the current workspace. * For all source files, look for comment lines containing the word * "copyright" and make sure at least one of them contains the current year. */ @Override() public void execute() { // Get a sorted list of the files in the schema directory. TreeSet<String> schemaFileNames = new TreeSet<String>(); for (File f : new File(schemaDirectory).listFiles()) { if (f.isFile()) { schemaFileNames.add(f.getName()); } } // Create a set of lists that will hold the schema elements read from the // files. LinkedList<String> attributeTypes = new LinkedList<String>(); LinkedList<String> objectClasses = new LinkedList<String>(); LinkedList<String> nameForms = new LinkedList<String>(); LinkedList<String> ditContentRules = new LinkedList<String>(); LinkedList<String> ditStructureRules = new LinkedList<String>(); LinkedList<String> matchingRuleUses = new LinkedList<String>(); // Open each of the files in order and read the elements that they contain, // appending them to the appropriate lists. for (String name : schemaFileNames) { // Read the contents of the file into a list with one schema element per // list element. LinkedList<StringBuilder> lines = new LinkedList<StringBuilder>(); try { BufferedReader reader = new BufferedReader(new FileReader( new File(schemaDirectory, name))); while (true) { String line = reader.readLine(); if (line == null) { break; } else if (line.startsWith("#") || (line.length() == 0)) { continue; } else if (line.startsWith(" ")) { lines.getLast().append(line.substring(1)); } else { lines.add(new StringBuilder(line)); } } reader.close(); } catch (Exception e) { throw new BuildException("Error while reading schema file " + name + ": " + e, e); } // Iterate through each line in the list. Find the colon and get the // attribute name at the beginning. If it's someting that we don't // recognize, then skip it. Otherwise, add the X-SCHEMA-FILE extension // and add it to the appropriate schema element list. for (StringBuilder buffer : lines) { // Get the line and add the X-SCHEMA-FILE extension to the end of it. // All of them should end with " )" but some might have the parenthesis // crammed up against the last character so deal with that as well. String line = buffer.toString().trim(); if (line.endsWith(" )")) { line = line.substring(0, line.length()-1) + "X-SCHEMA-FILE '" + name + "' )"; } else if (line.endsWith(")")) { line = line.substring(0, line.length()-1) + " X-SCHEMA-FILE '" + name + "' )"; } else { continue; } String lowerLine = line.toLowerCase(); if (lowerLine.startsWith("attributetypes:")) { attributeTypes.add(line); } else if (lowerLine.startsWith("objectclasses:")) { objectClasses.add(line); } else if (lowerLine.startsWith("nameforms:")) { nameForms.add(line); } else if (lowerLine.startsWith("ditcontentrules:")) { ditContentRules.add(line); } else if (lowerLine.startsWith("ditstructurerules:")) { ditStructureRules.add(line); } else if (lowerLine.startsWith("matchingruleuse:")) { matchingRuleUses.add(line); } } } // Write the resulting output to the merged schema file. try { BufferedWriter writer = new BufferedWriter(new FileWriter(toFile)); writer.write("dn: cn=schema"); writer.newLine(); writer.write("objectClass: top"); writer.newLine(); writer.write("objectClass: ldapSubentry"); writer.newLine(); writer.write("objectClass: subschema"); writer.newLine(); for (String line : attributeTypes) { writer.write(line); writer.newLine(); } for (String line : objectClasses) { writer.write(line); writer.newLine(); } for (String line : nameForms) { writer.write(line); writer.newLine(); } for (String line : ditContentRules) { writer.write(line); writer.newLine(); } for (String line : ditStructureRules) { writer.write(line); writer.newLine(); } for (String line : matchingRuleUses) { writer.write(line); writer.newLine(); } writer.close(); } catch (Exception e) { throw new BuildException("Error while writing concatenated schema file " + toFile + ": " + e, e); } } } sdk/build-tools/org/opends/build/tools/CoverageDiff.java
New file @@ -0,0 +1,969 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2008 Sun Microsystems, Inc. */ package org.opends.build.tools; import com.vladium.emma.report.*; import com.vladium.emma.report.html.doc.*; import com.vladium.emma.data.*; import com.vladium.util.IntObjectMap; import java.io.*; import java.util.*; import org.apache.tools.ant.Task; import org.apache.tools.ant.BuildException; import org.tmatesoft.svn.core.SVNDepth; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory; import org.tmatesoft.svn.core.wc.SVNClientManager; import org.tmatesoft.svn.core.wc.SVNDiffClient; import org.tmatesoft.svn.core.wc.SVNRevision; public class CoverageDiff extends Task { private static SVNClientManager ourClientManager = SVNClientManager.newInstance(); private static final String EOL = System.getProperty("line.separator"); private boolean verbose = false; private boolean enabled = true; private final int COVERED_MOD_EXE_LINES = 0; private final int MOD_EXE_LINES = 1; private final int MOD_LINES = 2; private final int DEL_LINES = 3; private final String ENCODING = "ISO-8859-1"; private final int IO_BUF_SIZE = 32 * 1024; private final LinkedHashMap<String, SrcFileItem> emmaSrcMap = new LinkedHashMap<String, SrcFileItem>(); private final LinkedHashMap<String, Double[]> modCoverageMap = new LinkedHashMap<String, Double[]>(); private final String CSS = "TABLE,TD,TH {border-style:solid; border-color:black;} " + "TD,TH {background:white;margin:0;line-height:100%;padding-left:0.5em;padding-right:0.5em;} " + "TD {border-width:0 1px 0 0;} TH {border-width:1px 1px 1px 0;} " + "TR TD.h {color:red;} " + "TABLE {border-spacing:0; border-collapse:collapse;border-width:0 0 1px 1px;} " + "P,H1,H2,H3,TH {font-family:verdana,arial,sans-serif;font-size:10pt;} " + "TD {font-family:courier,monospace;font-size:10pt;} " + "TABLE.hdft {border-spacing:0;border-collapse:collapse;border-style:none;} " + "TABLE.hdft TH,TABLE.hdft TD {border-style:none;line-height:normal;} " + "TABLE.hdft TH.tl,TABLE.hdft TD.tl {background:#6699CC;color:white;} " + "TABLE.hdft TD.nv {background:#6633DD;color:white;} " + ".nv A:link {color:white;} .nv A:visited {color:white;} " + ".nv A:active {color:yellow;} " + "TABLE.hdft A:link {color:white;} " + "TABLE.hdft A:visited {color:white;} " + "TABLE.hdft A:active {color:yellow;} " + ".in {color:#356085;} " + "TABLE.s TD {padding-left:0.25em;padding-right:0.25em;} " + "TABLE.s TD.ddt {padding-left:0.25em;padding-right:0.25em;color:#AAAAAA;}" + "TABLE.s TD.ds {padding-left:0.25em;padding-right:0.25em;text-align:right;background:#F0F0F0;} " + "TABLE.s TD.dm {padding-left:0.25em;padding-right:0.25em;text-align:right;background:#BCCFF9;} " + "TABLE.s TD.dd {padding-left:0.25em;padding-right:0.25em;text-align:right;background:#AAAAAA;color:#FFFFFF} " + "TABLE.s TH {padding-left:0.25em;padding-right:0.25em;text-align:left;background:#F0F0F0;} " + "TABLE.s TD.cz {background:#FF9999;} " + "TABLE.s TD.cp {background:#FFFF88;} " + "TABLE.s TD.cc {background:#CCFFCC;} " + "A:link {color:#0000EE;text-decoration:none;} " + "A:visited {color:#0000EE;text-decoration:none;} " + "A:hover {color:#0000EE;text-decoration:underline;} " + "TABLE.cn {border-width:0 0 1px 0;} " + "TABLE.s {border-width:1px 0 1px 1px;} " + "TD.h {color:red;border-width:0 1px 0 0;} " + "TD.f {border-width:0 1px 0 1px;} " + "TD.hf {color:red;border-width:0 1px 0 1px;} " + "TH.f {border-width:1px 1px 1px 1px;} " + "TR.cis TD {background:#F0F0F0;} " + "TR.cis TD {border-width:1px 1px 1px 0;} " + "TR.cis TD.h {color:red;border-width:1px 1px 1px 0;} " + "TR.cis TD.f {border-width:1px 1px 1px 1px;} " + "TR.cis TD.hf {color:red;border-width:1px 1px 1px 1px;} " + "TD.b {border-style:none;background:transparent;line-height:50%;} " + "TD.bt {border-width:1px 0 0 0;background:transparent;line-height:50%;} " + "TR.o TD {background:#F0F0F0;}" + "TABLE.it {border-style:none;}" + "TABLE.it TD,TABLE.it TH {border-style:none;}"; private File emmaDataPath; private File outputPath; private String diffPath; // The SVN revision to perform the diff against when calculating // the coverage diff. It can be a revision number, a timestamp, // or a revision keyword (BASE, COMMITTED, and PREV make the // most sense). The primary use case for this setting is to do // a coverage diff against the previous revision when there are // no changes in the working copy. It defaults to BASE. private String fromRevision; public void setEmmaDataPath(String file) { emmaDataPath = new File(file); } public void setOutputPath(String file) { outputPath = new File(file); } public void setDiffPath(String diffArgs) { diffPath = diffArgs; } public void setVerbose(String bol) { verbose = bol.toLowerCase().equals("true"); } public void setEnabled(String bol) { enabled = bol.toLowerCase().equals("true"); } public void setFromRevision(String fromRevision) { this.fromRevision = fromRevision; } public void execute() throws BuildException { try { innerExecute(); } catch (BuildException e) { throw e; } catch (Throwable e) { e.printStackTrace(); } } private void innerExecute() throws BuildException, SVNException { long start = System.currentTimeMillis(); verboseOut("Starting to execute coveragediff."); verboseOut("diffPath='" + diffPath +"'"); if(emmaDataPath == null) { throw new BuildException("emmaDataPath attribute is not set. It must be set to the path of the EMMA data directory"); } if(outputPath == null) { throw new BuildException("outputPath attribute is not set. It must be set to a valid directory where the report will be generated"); } if(fromRevision == null) { throw new BuildException("fromRevision attribute is not set. It must be set to the revision from which the diff is generated (e.g. BASE)."); } if(!enabled) { return; } // So we can go over http:// and https:// when diff'ing against previous versions DAVRepositoryFactory.setup(); IReportDataView emmaDataView = null; try { emmaDataView = loadEmmaData(emmaDataPath); verboseOut("Loaded EMMA data."); } catch(IOException ie) { System.out.println("WARNING: An error occurred while loading EMMA " + "data. Report will not contain any coverage information."); } try { processDiffOutput(getDiffOutputReader(), emmaDataView); } catch(IOException ie) { System.out.println("ERROR: An error occurred while processing diff output: " + ie.toString() + " Quitting..."); ie.printStackTrace(); return; } System.out.println("Coverage diff completed in " + (System.currentTimeMillis() - start) + " ms."); } private IReportDataView loadEmmaData(File emmaCoverageDataDir) throws IOException { if(emmaCoverageDataDir == null) { throw new IOException("Emma Converage Data Directory is null"); } File[] emmaCoverageDataFiles = emmaCoverageDataDir.listFiles(); int emmaCoverageDataFileCount = 0; IReportDataView m_view; IMetaData mdata = null; ICoverageData cdata = null; if(emmaCoverageDataFiles == null || emmaCoverageDataFiles.length <= 0) { throw new IOException("No EMMA data files found"); } verboseOut("processing input files ..."); final long start = System.currentTimeMillis(); // merge all data files: for (final File dataFile : emmaCoverageDataFiles) { verboseOut("processing input file [" + dataFile.getAbsolutePath() + "] ..."); final IMergeable[] fileData = DataFactory.load(dataFile); final IMetaData _mdata = (IMetaData) fileData[DataFactory.TYPE_METADATA]; if (_mdata != null) { verboseOut(" loaded " + _mdata.size() + " metadata entries"); if (mdata == null) mdata = _mdata; else mdata = (IMetaData) mdata.merge(_mdata); // note: later datapath entries override earlier ones } final ICoverageData _cdata = (ICoverageData) fileData[DataFactory.TYPE_COVERAGEDATA]; if (_cdata != null) { verboseOut(" loaded " + _cdata.size() + " coverage data entries"); if (cdata == null) cdata = _cdata; else cdata = (ICoverageData) cdata.merge(_cdata); // note: later datapath entries override earlier ones } ++emmaCoverageDataFileCount; } verboseOut(emmaCoverageDataFileCount + " file(s) read and merged in " + (System.currentTimeMillis() - start) + " ms"); if ((mdata == null) || mdata.isEmpty()) { System.out.println("nothing to do: no metadata found in any of the data files"); return null; } if (cdata == null) { System.out.println("nothing to do: no runtime coverage data found in any of the data files"); return null; } if (cdata.isEmpty()) { System.out.println("no collected coverage data found in any of the data files [Diff output will not include coverage data]"); return null; } if (!mdata.hasLineNumberData() || !mdata.hasSrcFileData()) { System.out.println("no collected line coverage data found in any of the data files [Diff output will not include coverage data]"); return null; } final IReportDataModel model = IReportDataModel.Factory.create (mdata, cdata); m_view = model.getView (IReportDataView.HIER_SRC_VIEW); verboseOut(" merged metadata contains " + mdata.size() + " entries"); verboseOut(" merged coverage data contains " + cdata.size() + " entries"); return m_view; } private BufferedReader getDiffOutputReader() throws IOException, SVNException { File workspaceRoot = getProject().getBaseDir(); File diffFile = new File(outputPath, "svn.diff"); // Most often this will be 'BASE' but it could also be 'PREVIOUS' SVNRevision baseRevision = SVNRevision.parse(fromRevision); System.out.println("Doing coverage diff from revision: " + baseRevision.toString()); ourClientManager.getDiffClient().doDiff(workspaceRoot, baseRevision, workspaceRoot, SVNRevision.WORKING, SVNDepth.INFINITY, false, new FileOutputStream(diffFile), null); return new BufferedReader(new InputStreamReader(new FileInputStream( diffFile))); } private void processDiffOutput(BufferedReader diffOutput, IReportDataView emmaDataView) throws IOException { File file = new File(outputPath, "index.html"); BufferedWriter writer = new BufferedWriter (new OutputStreamWriter ( new FileOutputStream (file), ENCODING), IO_BUF_SIZE); HTMLWriter out = new HTMLWriter(writer); System.out.println("Writing report to [" + file.toString() + "]"); String title = "Coverage Diff Report (generated "; title = title + new Date(System.currentTimeMillis ()); title = title + " )"; HTMLDocument page = new HTMLDocument (title, ENCODING); page.addStyle (CSS); String line = diffOutput.readLine(); ArrayList<String> diffOutputFile = new ArrayList<String>(); while(line != null) { //Diffed file if(line.length() >6 && line.substring(0, 6).equals("Index:")) { processDiffOutputFile(page, diffOutputFile, emmaDataView); diffOutputFile = new ArrayList<String>(); diffOutputFile.add(line); } else { diffOutputFile.add(line); } line = diffOutput.readLine(); } processDiffOutputFile(page, diffOutputFile, emmaDataView); IElementList overallStats = new ElementList(); final IElement statTitle = IElement.Factory.create (Tag.Hs[1]); statTitle.setText("OVERALL STATS SUMMARY", true); overallStats.add(statTitle); final HTMLTable statsTable = new HTMLTable (null, null, null, "0"); statsTable.setClass ("it"); { HTMLTable.IRow row = statsTable.newRow (); row.newCell ().setText ("svn diff arg(s):", true); row.newCell ().setText ("" + diffPath.toString(), true); row = statsTable.newRow (); row.newCell ().setText ("total files modified:", true); row.newCell ().setText ("" + emmaSrcMap.keySet().size(), false); Double[] overallModCoverage = new Double[4]; overallModCoverage[COVERED_MOD_EXE_LINES] = 0.0; overallModCoverage[MOD_EXE_LINES] = 0.0; overallModCoverage[MOD_LINES] = 0.0; overallModCoverage[DEL_LINES] = 0.0; Double[] modCoverage; for (Double[] doubles : modCoverageMap.values()) { modCoverage = doubles; if (modCoverage != null) { overallModCoverage[COVERED_MOD_EXE_LINES] += modCoverage[COVERED_MOD_EXE_LINES]; overallModCoverage[MOD_EXE_LINES] += modCoverage[MOD_EXE_LINES]; overallModCoverage[MOD_LINES] += modCoverage[MOD_LINES]; overallModCoverage[DEL_LINES] += modCoverage[DEL_LINES]; } } String modCoverageStr = ""; if(overallModCoverage[MOD_EXE_LINES] > 0) { modCoverageStr = String.format("%d%% (%.1f/%.1f)", (int)(overallModCoverage[COVERED_MOD_EXE_LINES]/overallModCoverage[MOD_EXE_LINES]*100), overallModCoverage[COVERED_MOD_EXE_LINES], overallModCoverage[MOD_EXE_LINES]); } else { modCoverageStr = String.format("%d%% (%.1f/%.1f)", 100, overallModCoverage[COVERED_MOD_EXE_LINES], overallModCoverage[MOD_EXE_LINES]); } row = statsTable.newRow (); row.newCell ().setText ("total lines modified:", true); row.newCell ().setText ("" + overallModCoverage[MOD_LINES].intValue(), true); row = statsTable.newRow (); row.newCell ().setText ("total lines removed:", true); row.newCell ().setText ("" + overallModCoverage[DEL_LINES].intValue(), true); row = statsTable.newRow (); row.newCell ().setText ("coverage for modified executable lines:", true); row.newCell ().setText ("" + modCoverageStr, true); } overallStats.add(statsTable); final IElement coverageTitle = IElement.Factory.create (Tag.Hs[1]); statTitle.setText("OVERALL DIFF SUMMARY", true); overallStats.add(coverageTitle); HTMLTable summaryTable = new HTMLTable ("100%", null, null, "0"); if(emmaDataView != null) { addHeaderRow(emmaDataView.getRoot(), summaryTable, true); } else { addHeaderRow(null, summaryTable, true); } Set<Map.Entry<String, SrcFileItem>> items = emmaSrcMap.entrySet(); boolean odd = true; int count = 0; for (Map.Entry<String, SrcFileItem> item : items) { if (item != null) { final String fileName = item.getKey(); final SrcFileItem srcFileItem = item.getValue(); final Double[] modCoverage = modCoverageMap.get(fileName); addItemRow(fileName, srcFileItem, modCoverage, odd, summaryTable, "s" + count, true, true); odd = !odd; count++; } } overallStats.add(summaryTable); page.setHeader(overallStats); page.emit(out); out.flush(); } private void processDiffOutputFile(HTMLDocument html, ArrayList<String> diffFile, IReportDataView emmaDataView) throws IOException { if(diffFile.size() <= 0) { return; } Double[] modCoverage = new Double[4]; modCoverage[COVERED_MOD_EXE_LINES] = 0.0; modCoverage[MOD_EXE_LINES] = 0.0; modCoverage[MOD_LINES] = 0.0; modCoverage[DEL_LINES] = 0.0; String fileHeader = diffFile.get(0); verboseOut("fileHeader: " + diffFile); //Try to get the package information if its a Java file File srcFilePath = new File(fileHeader.substring(7)); SrcFileItem emmaSourceItem = null; if(srcFilePath.isFile()) { FileInputStream srcFile = new FileInputStream(srcFilePath); String srcFilePackage = parseJavaPackage(srcFile); if(emmaDataView != null) { emmaSourceItem = getEmmaSrcItem(emmaDataView.getRoot(), srcFilePackage, srcFilePath.getName()); } } //Figure out the flag for the working copy. String workingCopyFlag = null; String otherCopyFlag = null; String firstFileLine = diffFile.get(2); String secondFileLine = diffFile.get(3); verboseOut("firstFileLine=" + firstFileLine); verboseOut("secondFileLine=" + secondFileLine); String revisionStr = "unknown"; // Skip over binary files if (firstFileLine.contains("Cannot display")) { return; } HTMLTable srcTable = null; if(firstFileLine.endsWith("(working copy)")) { workingCopyFlag = firstFileLine.substring(0, 1); } else { otherCopyFlag = firstFileLine.substring(0, 1); revisionStr = firstFileLine.substring(firstFileLine.lastIndexOf("(")); } if(secondFileLine.endsWith("(working copy)")) { workingCopyFlag = secondFileLine.substring(0, 1); } else { otherCopyFlag = secondFileLine.substring(0, 1); revisionStr = secondFileLine.substring(secondFileLine.lastIndexOf("(")); } if(firstFileLine.endsWith("(revision 0)") || secondFileLine.endsWith("(revision 0)")) { workingCopyFlag = "+"; otherCopyFlag = "-"; } if(workingCopyFlag == null || otherCopyFlag == null) { throw new IOException("Error occurred while parsing diff output." + EOL + "firstFileLine= '" + firstFileLine + "'" + EOL + "secondFileLine= '" + secondFileLine + "'"); } else { srcTable = new HTMLTable ("100%", null, null, "0"); srcTable.setClass("s"); ArrayList<String> diffOutputChunk = new ArrayList<String>(); Double[] chunkModCoverage; for(int i = 4; i < diffFile.size(); i++) { //Found a chunk indicator. if(diffFile.get(i).startsWith("@@")) { chunkModCoverage = processDiffOutputFileChunk(srcTable, diffOutputChunk, workingCopyFlag, otherCopyFlag, emmaSourceItem); if(chunkModCoverage != null) { modCoverage[COVERED_MOD_EXE_LINES] += chunkModCoverage[COVERED_MOD_EXE_LINES]; modCoverage[MOD_EXE_LINES] += chunkModCoverage[MOD_EXE_LINES]; modCoverage[MOD_LINES] += chunkModCoverage[MOD_LINES]; modCoverage[DEL_LINES] += chunkModCoverage[DEL_LINES]; } diffOutputChunk = new ArrayList<String>(); diffOutputChunk.add(diffFile.get(i)); } //Not any of the above so this line must be diffed text else { diffOutputChunk.add(diffFile.get(i)); } } //Finishing process whatever we have queued up chunkModCoverage = processDiffOutputFileChunk(srcTable, diffOutputChunk, workingCopyFlag, otherCopyFlag, emmaSourceItem); if(chunkModCoverage != null) { modCoverage[COVERED_MOD_EXE_LINES] += chunkModCoverage[COVERED_MOD_EXE_LINES]; modCoverage[MOD_EXE_LINES] += chunkModCoverage[MOD_EXE_LINES]; modCoverage[MOD_LINES] += chunkModCoverage[MOD_LINES]; modCoverage[DEL_LINES] += chunkModCoverage[DEL_LINES]; } } final IElement a = IElement.Factory.create (Tag.A); a.getAttributes ().set (Attribute.NAME, "s" + emmaSrcMap.keySet().size()); html.add(a); final IElement itemname = IElement.Factory.create (Tag.SPAN); { itemname.setText (srcFilePath.toString(), true); itemname.setClass ("in"); } final IElementList title = new ElementList (); { title.add (new Text ("DIFF SUMMARY FOR SOURCE FILE [", true)); title.add (itemname); title.add (new Text ("] against ", true)); title.add (new Text (revisionStr, true)); } html.addH (1, title, null); if(emmaSourceItem != null) { final HTMLTable coverageTable = new HTMLTable ("100%", null, null, "0"); addHeaderRow(emmaSourceItem, coverageTable, false); addItemRow(srcFilePath.toString(), emmaSourceItem, modCoverage, false, coverageTable, null, false, false); html.add(coverageTable); html.addEmptyP(); } else { html.addH(2, "Coverage Information Not Available (e.g. file is not in src/, is not java, is an interface, or was deleted)", null); } if(srcTable != null) { html.add(srcTable); } emmaSrcMap.put(srcFilePath.toString(), emmaSourceItem); modCoverageMap.put(srcFilePath.toString(), modCoverage); } private Double[] processDiffOutputFileChunk(HTMLTable table, ArrayList<String> diffChunk, String workingCopyFlag, String otherCopyFlag, SrcFileItem emmaSrcItem) { if(diffChunk.size() <= 0) { return null; } int workingCopyBegin; int workingCopyRange; int otherCopyBegin; int otherCopyRange; Double[] modCoverage = new Double[4]; modCoverage[COVERED_MOD_EXE_LINES] = 0.0; modCoverage[MOD_EXE_LINES] = 0.0; modCoverage[MOD_LINES] = 0.0; modCoverage[DEL_LINES] = 0.0; IntObjectMap lineCoverageMap = null; if(emmaSrcItem != null) { lineCoverageMap = emmaSrcItem.getLineCoverage (); } String chunkHeader = diffChunk.get(0); int workingCopyBeginIdx = chunkHeader.indexOf(workingCopyFlag); int workingCopyCommaIdx = chunkHeader.indexOf(",", workingCopyBeginIdx); int workingCopyEndIdx = chunkHeader.indexOf(" ", workingCopyCommaIdx); int otherCopyBeginIdx = chunkHeader.indexOf(otherCopyFlag); int otherCopyCommaIdx = chunkHeader.indexOf(",", otherCopyBeginIdx); int otherCopyEndIdx = chunkHeader.indexOf(" ", otherCopyCommaIdx); workingCopyBegin = Integer.parseInt( chunkHeader.substring(workingCopyBeginIdx + 1, workingCopyCommaIdx)); workingCopyRange = Integer.parseInt( chunkHeader.substring(workingCopyCommaIdx + 1, workingCopyEndIdx)); otherCopyBegin = Integer.parseInt( chunkHeader.substring(otherCopyBeginIdx + 1, otherCopyCommaIdx)); otherCopyRange = Integer.parseInt( chunkHeader.substring(otherCopyCommaIdx + 1, otherCopyEndIdx)); String chunkLine; SrcFileItem.LineCoverageData lCoverageData = null; int workingCopyLine = workingCopyBegin; int otherCopyLine = otherCopyBegin; final HTMLTable.IRow chunkRow = table.newTitleRow(); final HTMLTable.ICell chunkCell = chunkRow.newCell(); chunkCell.setColspan(2); chunkCell.setText("Lines " + workingCopyBegin + " - " + String.valueOf(workingCopyLine + workingCopyRange), true); for(int i = 1; i < diffChunk.size(); i++) { chunkLine = diffChunk.get(i); if(lineCoverageMap != null) { lCoverageData = (SrcFileItem.LineCoverageData) lineCoverageMap.get (workingCopyLine); } final HTMLTable.IRow srcRow = table.newRow(); final HTMLTable.ICell lineNumCell = srcRow.newCell(); final HTMLTable.ICell lineTxtCell = srcRow.newCell(); if (chunkLine.length() == 0) { lineTxtCell.setText(" ", true); } else { lineTxtCell.setText(chunkLine.substring(1), true); } //This line is either a modified line or a unchanged line if(!chunkLine.startsWith(otherCopyFlag)) { lineNumCell.setText(String.valueOf(workingCopyLine), true); //Determine if this line is a modified line or a unchange line if(chunkLine.startsWith(workingCopyFlag)) { lineNumCell.setClass("dm"); modCoverage[MOD_LINES] ++; if(lCoverageData != null) { modCoverage[MOD_EXE_LINES] ++; switch(lCoverageData.m_coverageStatus) { case SrcFileItem.LineCoverageData.LINE_COVERAGE_ZERO: lineTxtCell.setClass ("cz"); break; case SrcFileItem.LineCoverageData.LINE_COVERAGE_PARTIAL: lineTxtCell.setClass ("cp"); modCoverage[COVERED_MOD_EXE_LINES] += 0.5; break; case SrcFileItem.LineCoverageData.LINE_COVERAGE_COMPLETE: lineTxtCell.setClass ("cc"); modCoverage[COVERED_MOD_EXE_LINES] ++; break; default: } } } else { lineNumCell.setClass("ds"); } } else { lineNumCell.setClass("dd"); lineNumCell.setText(String.valueOf(otherCopyLine), true); lineTxtCell.setClass("ddt"); modCoverage[DEL_LINES] ++; } if(!chunkLine.startsWith(otherCopyFlag)) { workingCopyLine++; } if(!chunkLine.startsWith(workingCopyFlag)) { otherCopyLine++; } } return modCoverage; } private String parseJavaPackage(FileInputStream srcFile) throws IOException { BufferedReader srcFileReader = new BufferedReader( new InputStreamReader(srcFile)); String line = srcFileReader.readLine(); while(line != null) { int beginIdx = line.indexOf("package"); if(beginIdx > -1) { int endIdx = line.indexOf(";", beginIdx); if(endIdx > -1) { return line.substring(beginIdx + 7, endIdx).trim(); } } line = srcFileReader.readLine(); } return null; } private SrcFileItem getEmmaSrcItem(IItem rootItem, String srcPackageName, String srcFileName) { if(rootItem == null || srcPackageName == null || srcFileName == null) { return null; } for(Iterator packages = rootItem.getChildren(); packages.hasNext();) { IItem packageItem = (IItem)packages.next(); if(packageItem.getName().equals(srcPackageName)) { for(Iterator sources = packageItem.getChildren(); sources.hasNext();) { SrcFileItem sourceItem = (SrcFileItem)sources.next(); if(sourceItem.getName().equals(srcFileName)) { return sourceItem; } } } } return null; } private void addHeaderRow (final IItem item, final HTMLTable table, boolean includeName) { // header row: final HTMLTable.IRow header = table.newTitleRow (); if(includeName) { final HTMLTable.ICell nameCell = header.newCell(); nameCell.setText("File", true); } for (int c = 1; c <= 4; ++ c) { IItemAttribute attr = null; if(item != null) { attr = item.getAttribute (c, 0); } if (attr != null) { final HTMLTable.ICell cell = header.newCell (); cell.setText (attr.getName (), true); } else { final HTMLTable.ICell cell = header.newCell (); cell.setText (" ", true); } } if(item != null) { final HTMLTable.ICell cell = header.newCell(); cell.setText("mod lines, %", true); } else { final HTMLTable.ICell cell = header.newCell (); cell.setText (" ", true); } } /* * No header row, just data rows. */ private void addItemRow (final String fileName, final IItem item, final Double[] modCoverage, final boolean odd, final HTMLTable table, final String nameHREF, final boolean anchor, final boolean includeName) { final HTMLTable.IRow row = table.newRow (); if (odd) row.setClass ("o"); if(includeName) { final HTMLTable.ICell nameCell = row.newCell(); if(nameHREF != null) { final String fullHREFName = anchor ? "#".concat (nameHREF) : nameHREF; nameCell.add(new HyperRef(fullHREFName, fileName, true)); } else { nameCell.setText(fileName, true); } } final StringBuffer buf = new StringBuffer (11); for (int c = 1; c <=4; ++ c) { IItemAttribute attr = null; if(item != null) { attr = item.getAttribute (c, 0); } if (attr != null) { final HTMLTable.ICell cell = row.newCell (); //final boolean fail = (m_metrics [attrID] > 0) && ! attr.passes (item, m_metrics [attrID]); buf.setLength (0); attr.format (item, buf); cell.setText (buf.toString (), true); //if (fail) cell.setClass (CSS_DATA_HIGHLIGHT); } else { final HTMLTable.ICell cell = row.newCell (); cell.setText (" ", true); } } if(item != null && modCoverage != null) { String modCoverageStr = ""; if(modCoverage[1] > 0) { modCoverageStr = String.format("%d%% (%.1f/%.1f)", (int)(modCoverage[COVERED_MOD_EXE_LINES]/modCoverage[MOD_EXE_LINES]*100), modCoverage[COVERED_MOD_EXE_LINES], modCoverage[MOD_EXE_LINES]); } else { modCoverageStr = String.format("%d%% (%.1f/%.1f)", 100, modCoverage[COVERED_MOD_EXE_LINES], modCoverage[MOD_EXE_LINES]); } final HTMLTable.ICell cell = row.newCell(); cell.setText(modCoverageStr, true); } else { final HTMLTable.ICell cell = row.newCell (); cell.setText (" ", true); } } // Enable this with -Dtest.diff.verbose=true from the commandline private void verboseOut(Object msg) { if (verbose) { System.out.println(msg.toString()); } } } sdk/build-tools/org/opends/build/tools/CreateVersionString.java
New file @@ -0,0 +1,98 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2008 Sun Microsystems, Inc. */ package org.opends.build.tools; import java.text.DecimalFormat; import org.apache.tools.ant.Task; /** * This class provides an implemenation of an Ant task that may be used to * construct the full version number string that the Directory Server should * use. The value of the version number string will be stored in an Ant * property. */ public class CreateVersionString extends Task { // The name of the property in which the revision number should be set. private String propertyName = null; /** * Specifies the name of the Ant property into which the Subversion revision * number will be stored. * * @param propertyName The name of the Ant property into which the * Subversion revision number will be stored. */ public void setProperty(String propertyName) { this.propertyName = propertyName; } /** * Performs the appropriate processing needed for this task. In this case, * it uses SVNKit to identify the current revision number for the local * workspace and store it in a specified property. */ @Override() public void execute() { StringBuilder versionString = new StringBuilder(); versionString.append(getProject().getProperty("MAJOR_VERSION")); versionString.append("."); versionString.append(getProject().getProperty("MINOR_VERSION")); versionString.append("."); versionString.append(getProject().getProperty("POINT_VERSION")); String versionQualifier = getProject().getProperty("VERSION_QUALIFIER"); versionString.append(versionQualifier); try { int buildNumber = Integer.parseInt(getProject().getProperty("BUILD_NUMBER")); if (buildNumber > 0) { versionString.append("-build"); versionString.append(new DecimalFormat("000").format(buildNumber)); } } catch (NumberFormatException nfe) {} getProject().setNewProperty(propertyName, versionString.toString()); } } sdk/build-tools/org/opends/build/tools/GenerateMessageFile.java
New file @@ -0,0 +1,995 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2008 Sun Microsystems, Inc. */ package org.opends.build.tools; import org.apache.tools.ant.Task; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Location; import static org.opends.build.tools.Utilities.*; import org.opends.messages.Category; import org.opends.messages.Severity; import org.opends.messages.MessageDescriptor; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.DataOutputStream; import java.io.IOException; import java.util.Properties; import java.util.List; import java.util.ArrayList; import java.util.UnknownFormatConversionException; import java.util.Calendar; import java.util.Arrays; import java.util.Locale; import java.util.Map; import java.util.TreeMap; import java.util.HashSet; import java.util.Set; import java.util.EnumSet; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Generates a Java class containing representations of messages * found in a properties file. */ public class GenerateMessageFile extends Task { private File source; private File dest; private boolean overwrite; static private final String MESSAGES_FILE_STUB = "resource/Messages.java.stub"; /* * The registry filename is the result of the concatenation of the * location of where the source are generated, the package name and the * DESCRIPTORS_REG value. */ static private String REGISTRY_FILE_NAME; static private final String DESCRIPTORS_REG = "descriptors.reg"; /** * Used to set a category for all messages in the property file. * If set, the category for each message need not be encoded in * the message's property file key. */ static private final String GLOBAL_CATEGORY = "global.category"; /** * Used to set a severity for all messages in the property file. * If set, the severity for each message need not be encoded in * the message's property file key. */ static private final String GLOBAL_SEVERITY = "global.severity"; /** * Used to set a category mask for all messages in the property * file. If set, the category will automatically be assigned * USER_DEFINED and the value of <code>GLOBAL_CATEGORY</code> * will be ignored. */ static private final String GLOBAL_CATEGORY_MASK = "global.mask"; /** * When true generates messages that have no ordinals. */ static private final String GLOBAL_ORDINAL = "global.ordinal"; /** * When true and if the Java Web Start property is set use the class loader of * the jar where the MessageDescriptor is contained to retrieve the * ResourceBundle. */ static private final String GLOBAL_USE_MESSAGE_JAR_IF_WEBSTART = "global.use.message.jar.if.webstart"; static private final Set<String> DIRECTIVE_PROPERTIES = new HashSet<String>(); static { DIRECTIVE_PROPERTIES.add(GLOBAL_CATEGORY); DIRECTIVE_PROPERTIES.add(GLOBAL_CATEGORY_MASK); DIRECTIVE_PROPERTIES.add(GLOBAL_SEVERITY); DIRECTIVE_PROPERTIES.add(GLOBAL_ORDINAL); DIRECTIVE_PROPERTIES.add(GLOBAL_USE_MESSAGE_JAR_IF_WEBSTART); } static private final String SPECIFIER_REGEX = "%(\\d+\\$)?([-#+ 0,(\\<]*)?(\\d+)?(\\.\\d+)?([tT])?([a-zA-Z%])"; private final Pattern SPECIFIER_PATTERN = Pattern.compile(SPECIFIER_REGEX); /** * Message giving formatting rules for string keys. */ static public String KEY_FORM_MSG; static { KEY_FORM_MSG = new StringBuilder() .append(".\n\nOpenDS message property keys must be of the form\n\n") .append("\t\'[CATEGORY]_[SEVERITY]_[DESCRIPTION]_[ORDINAL]\'\n\n") .append("where\n\n") .append("CATEGORY is one of ") .append(EnumSet.allOf(Category.class)) .append("\n\nSEVERITY is one of ") .append(Severity.getPropertyKeyFormSet().toString()) .append("\n\nDESCRIPTION is a descriptive string composed ") .append("of uppercase character, digits and underscores ") .append("describing the purpose of the message ") .append("\n\nORDINAL is an integer between 0 and 65535 that is ") .append("unique to other messages defined in this file.\n\n") .append("You can relax the mandate for including the CATEGORY, ") .append("SEVERITY, and/or ORDINAL by including one or more ") .append("of the following respective property directives in your ") .append("properties file: ") .append(GLOBAL_CATEGORY) .append(", ") .append(GLOBAL_SEVERITY) .append(", ") .append(GLOBAL_ORDINAL) .append("and setting their value appropriately.") .toString(); } /* * ISO_LANGUAGES contains all official supported languages for i18n */ private static final List<String> ISO_LANGUAGES = Arrays.asList(Locale.getISOLanguages()); /* * ISO_COUNTRIES contains all official supported countries for i18n */ private static final List<String> ISO_COUNTRIES = Arrays.asList(Locale.getISOCountries()); /* * A Pattern instance that matches "<label>_<language>_<country>.properties" * where <label> can be anything including '_' * <language> a two characters code contained in the ISO_LANGUAGES list * <country> a two characters code contained in the ISO_COUNTRIES list */ private static final Pattern LANGUAGE_COUNTRY_MATCHER = Pattern.compile("(.*)_([a-z]{2})_([A-Z]{2}).properties"); /* * A Pattern instance that matches "<label>_<language>.properties" * where <label> and <language> have same definition as above. */ private static final Pattern LANGUAGE_MATCHER = Pattern.compile("(.*)_([a-z]{2}).properties"); /** * Representation of a format specifier (for example %s). */ private class FormatSpecifier { private String[] sa; /** * Creates a new specifier. * @param sa specifier components */ FormatSpecifier(String[] sa) { this.sa = sa; } /** * Indicates whether or not the specifier uses arguement * indexes (for example 2$). * @return boolean true if this specifier uses indexing */ public boolean specifiesArgumentIndex() { return this.sa[0] != null; } /** * Returns a java class associated with a particular formatter * based on the conversion type of the specifier. * @return Class for representing the type of arguement used * as a replacement for this specifier. */ public Class getSimpleConversionClass() { Class c = null; String sa4 = sa[4] != null ? sa[4].toLowerCase() : null; String sa5 = sa[5] != null ? sa[5].toLowerCase() : null; if ("t".equals(sa4)) { c = Calendar.class; } else if ( "b".equals(sa5)) { c = Boolean.class; } else if ( "h".equals(sa5)) { c = Integer.class; } else if ( "s".equals(sa5)) { c = CharSequence.class; } else if ( "c".equals(sa5)) { c = Character.class; } else if ( "d".equals(sa5) || "o".equals(sa5) || "x".equals(sa5) || "e".equals(sa5) || "f".equals(sa5) || "g".equals(sa5) || "a".equals(sa5)) { c = Number.class; } else if ( "n".equals(sa5) || "%".equals(sa5)) { // ignore literals } return c; } } /** * Represents a message to be written into the messages files. */ private class MessageDescriptorDeclaration { private MessagePropertyKey key; private String formatString; private List<FormatSpecifier> specifiers; private List<Class> classTypes; private String[] constructorArgs; /** * Creates a parameterized instance. * @param key of the message * @param formatString of the message */ public MessageDescriptorDeclaration(MessagePropertyKey key, String formatString) { this.key = key; this.formatString = formatString; this.specifiers = parse(formatString); this.classTypes = new ArrayList<Class>(); for (FormatSpecifier f : specifiers) { Class c = f.getSimpleConversionClass(); if (c != null) { classTypes.add(c); } } } /** * Gets the name of the Java class that will be used to represent * this message's type. * @return String representing the Java class name */ public String getDescriptorClassDeclaration() { StringBuilder sb = new StringBuilder(); if (useGenericMessageTypeClass()) { sb.append(getShortClassName(MessageDescriptor.class)); sb.append("."); sb.append(MessageDescriptor.DESCRIPTOR_CLASS_BASE_NAME); sb.append("N"); } else { sb.append(getShortClassName(MessageDescriptor.class)); sb.append("."); sb.append(MessageDescriptor.DESCRIPTOR_CLASS_BASE_NAME); sb.append(classTypes.size()); sb.append(getClassTypeVariables()); } return sb.toString(); } /** * Gets a string representing the message type class' variable * information (for example '<String,Integer>') that is based on * the type of arguments specified by the specifiers in this message. * @return String representing the message type class parameters */ public String getClassTypeVariables() { StringBuilder sb = new StringBuilder(); if (classTypes.size() > 0) { sb.append("<"); for (int i = 0; i < classTypes.size(); i++) { Class c = classTypes.get(i); if (c != null) { sb.append(getShortClassName(c)); if (i < classTypes.size() - 1) { sb.append(","); } } } sb.append(">"); } return sb.toString(); } /** * Gets the javadoc comments that will appear above the messages declaration * in the messages file. * @return String comment */ public String getComment() { StringBuilder sb = new StringBuilder(); sb.append(indent(1)).append("/**").append(EOL); // Unwrapped so that you can search through the descriptor // file for a message and not have to worry about line breaks String ws = formatString; // wrapText(formatString, 70); String[] sa = ws.split(EOL); for (String s : sa) { sb.append(indent(1)).append(" * ").append(s).append(EOL); } sb.append(indent(1)).append(" */").append(EOL); return sb.toString(); } /** * Sets the arguments that will be supplied in the declaration * of the message. * @param s array of string arguments that will be passed * in the constructor */ public void setConstructorArguments(String... s) { this.constructorArgs = s; } /** * {@inheritDoc} */ public String toString() { StringBuilder sb = new StringBuilder(); sb.append(getComment()); sb.append(indent(1)); sb.append("public static final "); sb.append(getDescriptorClassDeclaration()); sb.append(" "); sb.append(key.getMessageDescriptorName()); sb.append(" ="); sb.append(EOL); sb.append(indent(5)); sb.append("new "); sb.append(getDescriptorClassDeclaration()); sb.append("("); if (constructorArgs != null) { for (int i = 0; i < constructorArgs.length; i++) { sb.append(constructorArgs[i]); if (i < constructorArgs.length - 1) { sb.append(","); } } sb.append(", "); } sb.append("getClassLoader()"); sb.append(");"); return sb.toString(); } /** * Indicates whether the generic message type class should * be used. In general this is when a format specifier is * more complicated than we support or when the number of * arguments exceeeds the number of specific message type * classes (MessageType0, MessageType1 ...) that are defined. * @return boolean indicating */ private boolean useGenericMessageTypeClass() { if (specifiers.size() > MessageDescriptor.DESCRIPTOR_MAX_ARG_HANDLER) { return true; } else if (specifiers != null) { for (FormatSpecifier s : specifiers) { if (s.specifiesArgumentIndex()) { return true; } } } return false; } /** * Look for format specifiers in the format string. * @param s format string * @return list of format specifiers */ private List<FormatSpecifier> parse(String s) { List<FormatSpecifier> sl = new ArrayList<FormatSpecifier>(); Matcher m = SPECIFIER_PATTERN.matcher(s); int i = 0; while (i < s.length()) { if (m.find(i)) { // Anything between the start of the string and the beginning // of the format specifier is either fixed text or contains // an invalid format string. if (m.start() != i) { // Make sure we didn't miss any invalid format specifiers checkText(s.substring(i, m.start())); // Assume previous characters were fixed text //al.add(new FixedString(s.substring(i, m.start()))); } // Expect 6 groups in regular expression String[] sa = new String[6]; for (int j = 0; j < m.groupCount(); j++) { sa[j] = m.group(j + 1); } sl.add(new FormatSpecifier(sa)); i = m.end(); } else { // No more valid format specifiers. Check for possible invalid // format specifiers. checkText(s.substring(i)); // The rest of the string is fixed text //al.add(new FixedString(s.substring(i))); break; } } return sl; } private void checkText(String s) { int idx; // If there are any '%' in the given string, we got a bad format // specifier. if ((idx = s.indexOf('%')) != -1) { char c = (idx > s.length() - 2 ? '%' : s.charAt(idx + 1)); throw new UnknownFormatConversionException(String.valueOf(c)); } } } /** * Sets the source of the messages. * @param source File representing the properties * file containing messages */ public void setSourceProps(File source) { this.source = source; } /** * Sets the file that will be generated containing * declarations of messages from <code>source</code>. * @param dest File destination */ public void setDestJava(File dest) { this.dest = dest; /* * Set the descriptors.reg pathname to the same directory as the one used * to generate files and ensure all messages are generated in one place. */ String projectBase = null; try { projectBase = getProject().getBaseDir().getCanonicalPath(); } catch( java.io.IOException e) { throw new BuildException("Error processing " + dest + ": unable to retrieve project's directory of ant's project (" + e + ")"); } String registry = dest.getAbsolutePath(); // strip project directory prefix and replace properties filename with // $DESCRIPTORS_REG registry = registry.substring(projectBase.length()+1, registry.lastIndexOf(File.separator)+1) .concat(DESCRIPTORS_REG); if ( REGISTRY_FILE_NAME == null ) { REGISTRY_FILE_NAME = registry; } else { if ( ! REGISTRY_FILE_NAME.equals(registry) ) { // multiple messages are generated in several packages StringBuilder sb = new StringBuilder(); // full pathname of $REGISTRY_FILE_NAME sb.append(projectBase) .append(File.separator) .append(REGISTRY_FILE_NAME); // change from generated directory to properties files directory sb.replace(0, getProject().getProperty("msg.javagen.dir").length(), getProject().getProperty("msg.dir")); // replace properties filename with source filename sb.replace(sb.lastIndexOf(File.separator)+1, sb.length(), source.getName()); throw new BuildException("Error processing " + dest + ": all messages must be located in the same package thus " + "name of the source file should be " + sb); } } } /** * Indicates when true that an existing destination * file will be overwritten. * @param o boolean where true means overwrite */ public void setOverwrite(boolean o) { this.overwrite = o; } /** * {@inheritDoc} */ @Override public void execute() throws BuildException { if ( this.dest == null ) { // this is an example-plugin call: // - check the source file is not a localization // - guess the destination filename from source filename String sourcefilename = source.getAbsolutePath(); int filenameIndex = sourcefilename.lastIndexOf(File.separator)+1; String pathname = sourcefilename.substring(0, filenameIndex); String filename = sourcefilename.substring(filenameIndex); /* * Make sure only <label>.properties are generated thus avoiding to * generate messages for localized properties files. */ Matcher matcher = LANGUAGE_COUNTRY_MATCHER.matcher(filename); if ( matcher.find() ) { if ( ISO_LANGUAGES.contains(matcher.group(2)) && ISO_COUNTRIES.contains(matcher.group(3)) ) { // do not generate message for <label>_<language>_<country>.properties return; } } matcher = LANGUAGE_MATCHER.matcher(filename); if ( matcher.find() ) { if ( ISO_LANGUAGES.contains(matcher.group(2)) ) { // do not generate message for <label>_<language>.properties return; } } // filename without ".properties" filename = filename.substring(0, filename.length()-11); // change to src-generated directory keeping package name pathname = pathname.replace(getProject().getProperty("msg.dir"), getProject().getProperty("msg.javagen.dir")); // append characters from filename to pathname starting with an uppercase // letter, ignoring '_' and uppering all characters prefixed with "_" StringBuilder sb = new StringBuilder(pathname); boolean upperCaseNextChar = true; for(char c : filename.toCharArray()) { if ( c == '_' ) { upperCaseNextChar = true; continue; } if ( upperCaseNextChar ) { sb.append(Character.toUpperCase(c)); upperCaseNextChar = false; } else { sb.append(c); } } sb.append("Messages.java"); setDestJava(new File(sb.toString())); } BufferedReader stubReader = null; PrintWriter destWriter = null; try { // Decide whether to generate messages based on modification // times and print status messages. if (!source.exists()) { throw new BuildException("file " + source.getName() + " does not exist"); } if (dest.exists()) { if (this.overwrite || source.lastModified() > dest.lastModified()) { dest.delete(); log("Regenerating " + dest.getName() + " from " + source.getName()); } else { log(dest.getName() + " is up to date"); return; } } else { File javaGenDir = dest.getParentFile(); if (!javaGenDir.exists()) { javaGenDir.mkdirs(); } log("Generating " + dest.getName() + " from " + source.getName()); } stubReader = new BufferedReader(new InputStreamReader(getStubFile(), "UTF-8")); destWriter = new PrintWriter(dest, "UTF-8"); String stubLine; Properties properties = new Properties(); properties.load(new FileInputStream(source)); while (null != (stubLine = stubReader.readLine())) { if (stubLine.contains("${MESSAGES}")) { Integer globalOrdinal = null; String go = properties.getProperty(GLOBAL_ORDINAL); if (go != null) { globalOrdinal = new Integer(go); } // Determine the value of the global category/mask if set Integer globalMask = null; Category globalCategory = null; String gms = properties.getProperty(GLOBAL_CATEGORY_MASK); if (gms != null) { globalMask = Integer.parseInt(gms); globalCategory = Category.USER_DEFINED; } else { String gcs = properties.getProperty(GLOBAL_CATEGORY); if (gcs != null) { globalCategory = Category.valueOf(gcs); } } // Determine the value of the global severity Severity globalSeverity = null; String gss = properties.getProperty(GLOBAL_SEVERITY); if (gss != null) { globalSeverity = Severity.parseString(gss); } Map<MessagePropertyKey,String> keyMap = new TreeMap<MessagePropertyKey,String>(); for (Object propO : properties.keySet()) { String propKey = propO.toString(); try { if (!DIRECTIVE_PROPERTIES.contains(propKey)) { MessagePropertyKey key = MessagePropertyKey.parseString( propKey, globalCategory == null, globalSeverity == null, globalOrdinal == null); String formatString = properties.getProperty(propKey); keyMap.put(key, formatString); } } catch (IllegalArgumentException iae) { throw new BuildException( "ERROR: invalid property key " + propKey + ": " + iae.getMessage() + KEY_FORM_MSG); } } int usesOfGenericDescriptor = 0; Category firstCategory = null; Set<Integer> usedOrdinals = new HashSet<Integer>(); for (MessagePropertyKey key : keyMap.keySet()) { String formatString = keyMap.get(key); MessageDescriptorDeclaration message = new MessageDescriptorDeclaration(key, formatString); Category c = (globalCategory != null ? globalCategory : key.getCategory()); // Check that this category is the same as all the // others in this file. Maybe this should be an error? if (firstCategory != null) { if (!firstCategory.equals(c)) { log("WARNING: multiple categories defined in " + source); } } else { firstCategory = c; } Severity s = (globalSeverity != null ? globalSeverity : key.getSeverity()); if (c == null) { throw new BuildException( "No category could be assigned to message " + key + ". The category " + "must either be encoded in the property key or " + "or must be set by including the property " + GLOBAL_CATEGORY + " in the properties file" + KEY_FORM_MSG); } if (c == null) { throw new BuildException( "No severity could be assigned to message " + key + ". The severity " + "must either be encoded in the property key or " + "or must be set by including the property " + GLOBAL_SEVERITY + " in the properties file" + KEY_FORM_MSG); } if (globalOrdinal == null) { Integer ordinal = key.getOrdinal(); if (usedOrdinals.contains(ordinal)) { throw new BuildException( "The ordinal value \'" + ordinal + "\' in key " + key + " has been previously defined in " + source + KEY_FORM_MSG); } else { usedOrdinals.add(ordinal); } } message.setConstructorArguments( "BASE", quote(key.toString()), globalMask != null ? globalMask.toString() : c.name(), s.name(), globalOrdinal != null ? globalOrdinal.toString() : key.getOrdinal().toString() ); destWriter.println(message.toString()); destWriter.println(); // Keep track of when we use the generic descriptor // so that we can report it later if (message.useGenericMessageTypeClass()) { usesOfGenericDescriptor++; } } log(" Message Generated:" + keyMap.size(), Project.MSG_VERBOSE); log(" MessageDescriptor.ArgN:" + usesOfGenericDescriptor, Project.MSG_VERBOSE); } else { stubLine = stubLine.replace("${PACKAGE}", getPackage()); stubLine = stubLine.replace("${CLASS_NAME}", dest.getName().substring(0, dest.getName().length() - ".java".length())); stubLine = stubLine.replace("${BASE}", getBase()); String useMessageJarIfWebstart = properties.getProperty(GLOBAL_USE_MESSAGE_JAR_IF_WEBSTART); if ((useMessageJarIfWebstart != null) && ("true".equalsIgnoreCase(useMessageJarIfWebstart) || "on".equalsIgnoreCase(useMessageJarIfWebstart) || "true".equalsIgnoreCase(useMessageJarIfWebstart))) { useMessageJarIfWebstart = "true"; } else { useMessageJarIfWebstart = "false"; } stubLine = stubLine.replace("${USE_MESSAGE_JAR_IF_WEBSTART}", useMessageJarIfWebstart); destWriter.println(stubLine); } } registerMessageDescriptor(getMessageDescriptorFullClassName()); stubReader.close(); destWriter.close(); } catch (Exception e) { // Don't leave a malformed file laying around. Delete // it so it will be forced to be regenerated. if (dest.exists()) { dest.deleteOnExit(); } e.printStackTrace(); throw new BuildException("Error processing " + source + ": " + e.getMessage()); } finally { if (stubReader != null) { try { stubReader.close(); } catch (Exception e){ // ignore } } if (destWriter != null) { try { destWriter.close(); } catch (Exception e){ // ignore } } } } private String getMessageDescriptorFullClassName() { return getPackage() + "." + getMessageDescriptorClassName(); } private String getMessageDescriptorClassName() { return dest.getName().substring( 0, dest.getName().length() - ".java".length()); } private String getBase() { String srcPath = unixifyPath(source.getAbsolutePath()); String base = srcPath.substring(srcPath.lastIndexOf("/") + 1, srcPath.length() - ".properties".length()); return base; } private String getPackage() { String destPath = unixifyPath(dest.getAbsolutePath()); String msgJavaGenDir = unixifyPath( getProject().getProperty("msg.javagen.dir")); String c = destPath.substring(msgJavaGenDir.length()+1); c = c.replace('/', '.'); c = c.substring(0, c.lastIndexOf(".")); // strip .java c = c.substring(0, c.lastIndexOf(".")); // strip class name return c; } static private String indent(int indent) { char[] blankArray = new char[2 * indent]; Arrays.fill(blankArray, ' '); return new String(blankArray); } static private String quote(String s) { return new StringBuilder() .append("\"") .append(s) .append("\"") .toString(); } static private String getShortClassName(Class c) { String name; String fqName = c.getName(); int i = fqName.lastIndexOf('.'); if (i > 0) { name = fqName.substring(i + 1); } else { name = fqName; } return name; } /** * Writes a record in the messages registry for the specifed * class name. * @param descClassName name of the message descriptor class * @return true if the class was acutally added to the registry; * false indicates that the class was already present. * @throws IOException if there is a problem with the file I/O */ private boolean registerMessageDescriptor(String descClassName) throws IOException { boolean classAdded = false; File registry = getRegistryFile(); if (!isDescriptorRegistered(descClassName)) { FileOutputStream file = new FileOutputStream(registry,true); DataOutputStream out = new DataOutputStream(file); out.writeBytes(descClassName); out.writeBytes("\n"); out.flush(); out.close(); } return classAdded; } private boolean isDescriptorRegistered(String descClassName) throws IOException { boolean isRegistered = false; BufferedReader reader = new BufferedReader( new FileReader(getRegistryFile())); String line; while(null != (line = reader.readLine())) { if (line.trim().equals(descClassName.trim())) { isRegistered = true; break; } } return isRegistered; } private File getRegistryFile() throws IOException { File registry = new File(getProjectBase(), REGISTRY_FILE_NAME); if (!registry.exists()) { File parent = registry.getParentFile(); if (!parent.exists()) { parent.mkdirs(); } registry.createNewFile(); } return registry; } private File getProjectBase() { File projectBase; // Get the path to build.xml and return the parent // directory else just return the working directory. Location l = getLocation(); String fileName = l.getFileName(); if (fileName != null) { File f = new File(fileName); projectBase = f.getParentFile(); } else { projectBase = new File(System.getProperty("user.dir")); } return projectBase; } private String unixifyPath(String path) { return path.replace("\\", "/"); } /* * Returns the stub file ("resource/Messages.java.stub") from the appropriate * location: ant or jar file. */ private InputStream getStubFile() { InputStream result = null; File stub = new File(getProjectBase(), MESSAGES_FILE_STUB); if ( stub.exists() ) { // this is the OpenDS's ant project calling // Stub is located at OPENDS_ROOT/resource/Messages.java.stub try { result = new FileInputStream(stub); } catch (FileNotFoundException e) { // should neven happen throw new BuildException("Unable to load template " + MESSAGES_FILE_STUB + ": " + e.getMessage()); } } else { // this is the example plugin's ant project calling // Stub is located at build-tools.jar:resource/Messages.java.stub result = getClass().getResourceAsStream(MESSAGES_FILE_STUB); } return result; } /** * For testing. * @param args from command line */ public static void main(String[] args) { File source = new File("src/messages/messages/tools.properties"); File dest = new File("/tmp/org/opends/XXX.java"); GenerateMessageFile gmf = new GenerateMessageFile(); gmf.setOverwrite(true); gmf.setDestJava(dest); gmf.setSourceProps(source); gmf.execute(); } } sdk/build-tools/org/opends/build/tools/GenerateRpm.java
New file @@ -0,0 +1,251 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2007-2008 Sun Microsystems, Inc. */ package org.opends.build.tools; import org.apache.tools.ant.Task; import org.apache.tools.ant.BuildException; import static org.opends.build.tools.Utilities.*; import java.io.File; import java.io.PrintWriter; /** * Generates an RPM spec file. */ public class GenerateRpm extends Task { private File topDir; private String topDirAbsolutePath; private String sourceDirName; private File destFile; private String prefix; private String version; private String release; private boolean overwrite; private StringBuilder sb; private final String filePrefix="%{_prefix}"; private final String dirPrefix="%dir %{_prefix}"; /** * Sets the top directory for the rpm build. * @param topDir File representing top directory for rpm build directory */ public void setTopDir(File topDir) { this.topDir = topDir; topDirAbsolutePath = topDir.getAbsolutePath(); } /** * Sets the prefix for the RPM. * @param prefix Used for package relocation */ public void setPrefix(String prefix) { this.prefix = prefix; } /** * Sets the name of the source directory. * @param sourceDirName name of the source directory. */ public void setSourceDirName(String sourceDirName) { this.sourceDirName = sourceDirName; } /** * Sets the RPM spec file that will be generated. * @param dest The spec file * */ public void setSpecFileName(File dest) { this.destFile = dest; } /** * Sets the version number. * @param version The version number * */ public void setVersion(String version) { this.version = version; } /** * Sets the release number. * @param release The release number * */ public void setRelease(String release) { this.release = release; } /** * Indicates when true that an existing destination * file will be overwritten. * @param o boolean where true means overwrite */ public void setOverwrite(boolean o) { this.overwrite = o; } /** * {@inheritDoc} */ @Override public void execute() throws BuildException { try { if (!topDir.exists()) { throw new BuildException("directory " + topDir.getName() + " does not exist"); } if (!topDir.isDirectory()) { throw new BuildException(topDir.getName() + " is not a directory"); } if (destFile.exists()) { if (this.overwrite) { destFile.delete(); log("Regenerating " + destFile.getName() + " from " + topDir.getName()); } else { log(destFile.getName() + " has not been regenerated"); } } sb = new StringBuilder(); File rootDir = new File(sourceDirName); String opendsDir = rootDir.getName(); // Generate the package information sb.append("Summary : OpenDS Directory Server" + EOL); sb.append("Name : opends" + EOL); sb.append("Version : " + version + EOL); sb.append("Release : " + release + EOL); sb.append("License : CDDL" + EOL); sb.append("Group : Applications/Network" + EOL); sb.append("URL : https://opends.org" + EOL); sb.append( EOL); sb.append("BuildArchitectures : noarch" + EOL); sb.append("BuildRoot : " + topDirAbsolutePath + "/SOURCES"+ EOL); sb.append("Prefix : " + prefix + EOL); sb.append( EOL); sb.append("%define _prefix " + prefix + EOL); sb.append( EOL); sb.append("%Description" + EOL); sb.append("OpenDS Directory Server" + EOL); sb.append( EOL); sb.append("# =========================" + EOL); sb.append("# pre/post installation" + EOL); sb.append("# =========================" + EOL); sb.append("# The order is:" + EOL); sb.append("# 1. %pre new" + EOL); sb.append("# 2. install new" + EOL); sb.append("# 3. %post new" + EOL); sb.append("# 4. %preun old" + EOL); sb.append("# 5. delete old" + EOL); sb.append("# 6. %postun old" + EOL); sb.append("# Note: \"$1 equals \"1\" it means \"fresh install\"" + EOL); sb.append( EOL); sb.append("# PRE INSTALL" + EOL); sb.append("%pre" + EOL); sb.append("if [ \"$1\" != \"1\" ]; then" + EOL); sb.append("echo \" This version of the OpenDS RPM does not work\""+ EOL); sb.append("echo \" with the standard RPM upgrade mechanism\"" + EOL); sb.append("echo \" (rpm -U or rpm -F).\"" + EOL); sb.append("echo \" To perform an upgrade, use the OpenDS upgrade\""+ EOL); sb.append("echo \" tool included in the package delivery.\"" + EOL); sb.append("echo \" For more information about the upgrade process\""+ EOL); sb.append("echo \" with RPM see https://www.opends.org/wiki//page/OpendsRPM.\""+ EOL); sb.append("exit 1" + EOL); sb.append("fi" + EOL); sb.append( EOL); sb.append("# POST INSTALL" + EOL); sb.append("%post" + EOL); sb.append( EOL); sb.append("# PRE UNINSTALL" + EOL); sb.append("%preun" + EOL); sb.append("${RPM_INSTALL_PREFIX}/OpenDS-1.0.0/bin/stop-ds" + EOL); sb.append( EOL); sb.append("# POST UNINSTALL" + EOL); sb.append("%postun" + EOL); sb.append("rm -rf ${RPM_INSTALL_PREFIX}/" + opendsDir + EOL); sb.append("rmdir --ignore-fail-on-non-empty ${RPM_INSTALL_PREFIX}" + EOL); sb.append( EOL); sb.append("# =========================" + EOL); sb.append("# Prepare, Build, Install" + EOL); sb.append("# =========================" + EOL); sb.append("%prep" + EOL); sb.append("cd "+ topDirAbsolutePath +"/SOURCES" + prefix + " ; cp -r " + sourceDirName + " ." + EOL); sb.append("%build" + EOL); sb.append("%install" + EOL); sb.append( EOL); sb.append("# =========================" + EOL); sb.append("# FILES LAYOUT" + EOL); sb.append("# =========================" + EOL); sb.append("%files" + EOL); sb.append(dirPrefix + EOL); generatedLevel("", rootDir); // flush the spec file. PrintWriter destWriter = new PrintWriter(destFile); destWriter.print(sb.toString()); destWriter.close(); } catch (Exception e) { // Don't leave a malformed file laying around. Delete // it so it will be forced to be regenerated. if (destFile.exists()) { destFile.deleteOnExit(); } e.printStackTrace(); throw new BuildException("Error processing " + topDir + ": " + e.getMessage()); } } private void generatedLevel (String parent, File source ) { if (source.isDirectory()) { sb.append(dirPrefix + parent + "/" +source.getName()); sb.append(EOL); for (File child : source.listFiles()) { generatedLevel( parent + "/" +source.getName(), child); } } else { sb.append(filePrefix + parent + "/" +source.getName()); sb.append(EOL); } } } sdk/build-tools/org/opends/build/tools/GetSubversionRevision.java
New file @@ -0,0 +1,143 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2008 Sun Microsystems, Inc. */ package org.opends.build.tools; import java.io.File; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.wc.SVNClientManager; import org.tmatesoft.svn.core.wc.SVNInfo; import org.tmatesoft.svn.core.wc.SVNRevision; /** * This class provides an implementation of an Ant task that may be used to * determine the current Subversion revision number of the current working * copy. The value of the revision number will be stored in an Ant property. */ public class GetSubversionRevision extends Task { // The name of the property in which the revision number should be set. private String propertyName = null; // The path to the root of the Subversion workspace for which to retrieve the // revision number. private String workspace = null; // The svn client manager. Required by svnkit 1.2.x private static SVNClientManager ourClientManager = SVNClientManager.newInstance(); /** * Specifies the name of the Ant property into which the Subversion revision * number will be stored. * * @param propertyName The name of the Ant property into which the * Subversion revision number will be stored. */ public void setProperty(String propertyName) { this.propertyName = propertyName; } /** * Specifies the path to the root of the Subversion workspace for which to * retrieve the revision number. * * @param workspace The path to the root of the Subversion workspace for * which to retrieve the revision number. */ public void setWorkspace(String workspace) { this.workspace = workspace; } /** * Performs the appropriate processing needed for this task. In this case, * it uses SVNKit to identify the current revision number for the local * workspace and store it in a specified property. */ @Override() public void execute() { if ((propertyName == null) || (propertyName.length() == 0)) { throw new BuildException("ERROR: No property was specified for " + "storing the revision number value."); } File workspacePath; if ((workspace == null) || (workspace.length() == 0)) { workspacePath = getProject().getBaseDir(); } else { workspacePath = new File(workspace); } try { SVNInfo svnInfo = ourClientManager.getWCClient().doInfo(workspacePath, SVNRevision.WORKING); SVNRevision revision = svnInfo.getCommittedRevision(); if (revision == null) { System.err.println("WARNING: Could not determine Subversion " + "revision number for current workspace."); getProject().setNewProperty(propertyName, "-1"); } else { getProject().setNewProperty(propertyName, String.valueOf(revision.getNumber())); } } catch (SVNException svnException) { System.err.println("WARNING: Could not determine Subversion " + "revision number for current workspace: " + svnException); getProject().setNewProperty(propertyName, "-1"); } } } sdk/build-tools/org/opends/build/tools/GetSubversionUrlRepo.java
New file @@ -0,0 +1,145 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2009 Sun Microsystems, Inc. */ package org.opends.build.tools; import java.io.File; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.wc.SVNClientManager; import org.tmatesoft.svn.core.wc.SVNInfo; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.SVNURL; /** * This class provides an implementation of an Ant task that may be used to * determine the current Subversion revision number of the current working * copy. The value of the revision number will be stored in an Ant property. */ public class GetSubversionUrlRepo extends Task { // The name of the property in which the revision number should be set. private String propertyName = null; // The path to the root of the Subversion workspace for which to retrieve the // revision number. private String workspace = null; // The svn client manager. Required by svnkit 1.2.x private static SVNClientManager ourClientManager = SVNClientManager.newInstance(); /** * Specifies the name of the Ant property into which the Subversion revision * number will be stored. * * @param propertyName The name of the Ant property into which the * Subversion revision number will be stored. */ public void setProperty(String propertyName) { this.propertyName = propertyName; } /** * Specifies the path to the root of the Subversion workspace for which to * retrieve the revision number. * * @param workspace The path to the root of the Subversion workspace for * which to retrieve the revision number. */ public void setWorkspace(String workspace) { this.workspace = workspace; } /** * Performs the appropriate processing needed for this task. In this case, * it uses SVNKit to identify the current revision number for the local * workspace and store it in a specified property. */ @Override() public void execute() { if ((propertyName == null) || (propertyName.length() == 0)) { throw new BuildException("ERROR: No property was specified for " + "storing the revision number value."); } File workspacePath; if ((workspace == null) || (workspace.length() == 0)) { workspacePath = getProject().getBaseDir(); } else { workspacePath = new File(workspace); } try { SVNInfo svnInfo = ourClientManager.getWCClient().doInfo(workspacePath, SVNRevision.WORKING); SVNURL url_repo = svnInfo.getURL(); if (url_repo == null) { System.err.println("WARNING: Could not determine Subversion URL Repository " + "for current workspace."); getProject().setNewProperty(propertyName, "-1"); } else { getProject().setNewProperty(propertyName, String.valueOf(url_repo)); } } catch (SVNException svnException) { System.err.println("WARNING: Could not determine Subversion " + "URL repository for current workspace: " + svnException); getProject().setNewProperty(propertyName, "-1"); } } } sdk/build-tools/org/opends/build/tools/MessagePropertyKey.java
New file @@ -0,0 +1,267 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2008 Sun Microsystems, Inc. */ package org.opends.build.tools; import org.opends.messages.Category; import org.opends.messages.Severity; import java.util.EnumSet; /** * OpenDS messages defined in properties files must be defined * with the ordinal and in most cases category and severity encoded * in the message key. This class helps with generating and * parsing of these keys. * * Keys must be of the form * * CATEGORY_SEVERITY_DESCRIPTION_ORDINAL * * where: * <ul> * <li> * CATEGORY is the string representation of one of the * <code>Category</code> enums. * </li> * <li> * SEVERITY is the long or abbreviated form of one of * the <code>Severity</code> enums. * </li> * <li> * DESCRIPTION is an uppercase string containing characters * and the underscore character for describing the purpose * of the message. * </li> * <li> * ORDINAL is an integer that makes the message unique witin * the property file. * </li> * </ul> * */ // TODO: move this class to GenerateMessageFile when DirectoryServer // no longer needs to support dumpMessages() public class MessagePropertyKey implements Comparable<MessagePropertyKey> { private Category category; private Severity severity; private String description; private Integer ordinal; /** * Creates a message property key from a string value. * @param keyString from properties file * @param includesCategory when true expects ordinals to be encoded * in the keystring; when false the mandate is relaxed * @param includesSeverity when true expects ordinals to be encoded * in the keystring; when false the mandate is relaxed * @param includesOrdinal when true expects ordinals to be encoded * in the keystring; when false the mandate is relaxed * @return MessagePropertyKey created from string */ static public MessagePropertyKey parseString( String keyString, boolean includesCategory, boolean includesSeverity, boolean includesOrdinal) { Category category = null; Severity severity = null; String description; Integer ordinal = null; String k = keyString; for (Category c : EnumSet.allOf(Category.class)) { String cName = c.name(); if (k.startsWith(cName)) { category = c; if ('_' != k.charAt(cName.length())) { throw new IllegalArgumentException( "Error processing " + keyString + ". Category must be " + "separated from the rest of the " + "key with an '_' character"); } k = k.substring(cName.length() + 1); break; } } if (category == null && includesCategory) { throw new IllegalArgumentException("Category not included in key " + keyString); } for (Severity s : EnumSet.allOf(Severity.class)) { String sName = s.propertyKeyFormName(); if (k.startsWith(sName)) { severity = s; if ('_' != k.charAt(sName.length())) { throw new IllegalArgumentException( "Error processing " + keyString + ". Severity must be " + "separated from the rest of the " + "key with an '_' character"); } k = k.substring(sName.length() + 1); break; } } if (severity == null && includesSeverity) { throw new IllegalArgumentException("Severity not included in key " + keyString); } if (includesOrdinal) { int li = k.lastIndexOf("_"); if (li != -1) { description = k.substring(0, li).toUpperCase(); } else { throw new IllegalArgumentException( "Incorrectly formatted key " + keyString); } try { String ordString = k.substring(li + 1); ordinal = Integer.parseInt(ordString); } catch (Exception nfe) { throw new IllegalArgumentException("Error parsing ordinal for key " + keyString); } } else { description = k; } return new MessagePropertyKey(category, severity, description, ordinal); } /** * Creates a parameterized instance. * @param category of this key * @param severity of this key * @param description of this key * @param ordinal of this key */ public MessagePropertyKey(Category category, Severity severity, String description, Integer ordinal) { this.category = category; this.severity = severity; this.description = description; this.ordinal = ordinal; } /** * Gets the category of this key. * @return Category of this key */ public Category getCategory() { return this.category; } /** * Gets the severity of this key. * @return Severity of this key */ public Severity getSeverity() { return this.severity; } /** * Gets the description of this key. * @return description of this key */ public String getDescription() { return this.description; } /** * Gets the ordinal of this key. * @return ordinal of this key */ public Integer getOrdinal() { return this.ordinal; } /** * Gets the name of the MessageDescriptor as it should appear * in the messages file. * @return name of message descriptor */ public String getMessageDescriptorName() { return new StringBuilder() .append(this.severity.messageDesciptorName()) .append("_") .append(this.description).toString(); } /** * {@inheritDoc} */ public String toString() { return getPropertyKeyName(true, true, true); } /** * Gets the name of the key as it would appear in a properties file. * @param includeCategory in the name * @param includeSeverity in the name * @param includeOrdinal in the name * @return string representing the property key */ public String getPropertyKeyName(boolean includeCategory, boolean includeSeverity, boolean includeOrdinal) { StringBuilder sb = new StringBuilder(); if (category != null && includeCategory) { sb.append(category.name()); sb.append("_"); } if (severity != null && includeSeverity) { sb.append(severity.propertyKeyFormName()); sb.append("_"); } sb.append(description); if (ordinal != null && includeOrdinal) { sb.append("_"); sb.append(ordinal); } return sb.toString(); } /** * {@inheritDoc} */ public int compareTo(MessagePropertyKey k) { if (ordinal == k.ordinal) { return description.compareTo(k.description); } else { return ordinal.compareTo(k.ordinal); } } } sdk/build-tools/org/opends/build/tools/PrepTestNG.java
New file @@ -0,0 +1,337 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2006-2008 Sun Microsystems, Inc. */ package org.opends.build.tools; import java.io.FileOutputStream; import java.io.PrintStream; import java.io.BufferedReader; import java.io.FileReader; import java.util.Arrays; import org.apache.tools.ant.Task; import org.apache.tools.ant.BuildException; public class PrepTestNG extends Task { /** Template for inserting children elements of default test tag */ static private final String DEFAULT_TAGS_TEMPLATE = "<!-- DO NOT REMOVE! - GENERATED DEFAULT TAGS (see PrepTestNG class) -->"; /** Template for inserting global children elements of run tags */ static private final String GLOBAL_RUN_TAGS_TEMPLATE = "<!-- DO NOT REMOVE! - GENERATED GLOBAL RUN TAGS (see PrepTestNG class) -->"; /** Indentation used in testng.xml */ static private final int INDENT = 4; private String file; private String toFile; private String groupList; private String packageList; private String classList; private String methodList; public void setFile(String file) { this.file = file; } public void setToFile(String toFile) { this.toFile = toFile; } public void setGroupList(String groupList) { this.groupList = groupList; } public void setPackageList(String packageList) { this.packageList = packageList; } public void setClassList(String classList) { this.classList = classList; } public void setMethodList(String methodList) { this.methodList = methodList; } public void execute() throws BuildException { if(file == null) { throw new BuildException("Attribute file must be set to the orginal " + "TestNG XML file"); } if(toFile == null) { throw new BuildException("Attribute toFile must be set to the modified " + "TestNG XML file"); } BufferedReader reader; FileOutputStream outFile; PrintStream writer; String line; String[] groups; String[] packages; String[] classes; String[] methods; String[] groupLine; String[] methodLine; String methodClass; String methodName; int methodNameStartIdx; int groupCount = 0; int packageCount = 0; int classCount = 0; int methodCount = 0; try { reader = new BufferedReader(new FileReader(file)); outFile = new FileOutputStream(toFile); writer = new PrintStream(outFile); line = reader.readLine(); if(groupList != null && !groupList.trim().equals("") && !groupList.startsWith("${")) { groups = groupList.split(","); } else { groups = new String[0]; } if(packageList != null && !packageList.trim().equals("") && !packageList.startsWith("${")) { packages = packageList.split(","); } else { packages = new String[0]; } if(classList != null && !classList.trim().equals("") && !classList.startsWith("${")) { classes = classList.split(","); } else { classes = new String[0]; } if(methodList != null && !methodList.trim().equals("") && !methodList.startsWith("${")) { methods = methodList.split(";"); } else { methods = new String[0]; } while(line != null) { if(line.indexOf(DEFAULT_TAGS_TEMPLATE) >= 0) { int level = 2; if(groups.length > 0) { boolean windowsClause = false; println(writer, level, "<groups>"); println(writer, ++level, "<run>"); level++; for(String group : groups) { groupLine = group.split("="); if(groupLine.length == 2) { String inc_exc = groupLine[0].trim(); if (inc_exc == null || !("include".equals(inc_exc.toLowerCase()) || "exclude".equals(inc_exc.toLowerCase()))) { System.out.println("Error: illegal group clause " + group); } else { String gr = groupLine[1].trim(); println(writer, level, "<" +inc_exc +" "+ "name=\""+gr+ "\" />"); windowsClause |= "windows".equals(gr); groupCount++; } } } // Exclude windows specific tests if the user has not provided // an explicit windows clause and we're not on windows. if (!windowsClause && !isWindows()) { println(writer, level, "<exclude name=\"windows\"/>"); groupCount++; } println(writer, --level, "</run>"); println(writer, --level, "</groups>"); } else { // No explicit groups have been specified so see if we need // to exclude the windows tests. if (!isWindows()) { println(writer, level, "<groups>"); println(writer, ++level, "<run>"); println(writer, ++level, "<exclude name=\"windows\"/>"); println(writer, --level, "</run>"); println(writer, --level, "</groups>"); groupCount++; } } if(packages.length > 0) { println(writer, level, "<packages>"); level++; for(String pkg : packages) { println(writer, level, "<package name=\"" + pkg.trim() + "\" />"); packageCount++; } println(writer, --level, "</packages>"); } if(classes.length > 0 || methods.length > 0) { println(writer, level, "<classes>"); if(classes.length > 0) { level++; for(String cls : classes) { println(writer, level, "<class name=\"" + cls.trim() + "\" />"); classCount++; } } if(methods.length > 0) { level++; for(String mhd : methods) { methodLine = mhd.split(","); if(methodLine.length > 0) { // Allow class.method or class#method methodNameStartIdx = methodLine[0].lastIndexOf("#"); if (methodNameStartIdx == -1) { methodNameStartIdx = methodLine[0].lastIndexOf("."); } methodClass = methodLine[0].substring(0, methodNameStartIdx); methodName = methodLine[0].substring(methodNameStartIdx + 1, methodLine[0].length()); println(writer, level, "<class name=\"" + methodClass.trim() + "\" >"); println(writer, ++level, "<methods>"); println(writer, ++level, "<include name=\"" + methodName.trim() + "\" />"); methodCount++; classCount++; for(int i = 1; i < methodLine.length; i ++) { println(writer, level, "<include name=\"" + methodLine[i].trim() + "\" />"); methodCount++; } println(writer, --level, "</methods>"); println(writer, --level, "</class>"); } } } println(writer, --level, "</classes>"); } } else if (line.indexOf(GLOBAL_RUN_TAGS_TEMPLATE) != -1) { if (!isWindows()) { int index = line.indexOf(GLOBAL_RUN_TAGS_TEMPLATE); println(writer, levelForIndex(index), "<exclude name=\"windows\"/>"); } } else { println(writer, 0, line); } line = reader.readLine(); } System.out.println("Adding " + groupCount + " group tags, " + packageCount + " package tags, " + classCount + " class tags, " + methodCount + " method tags to " + toFile); } catch(Exception e) { throw new BuildException("File Error: " + e.toString()); } } static private boolean isWindows() { String os = System.getProperty("os.name"); return (os != null && os.toLowerCase().indexOf("windows") != -1); } static private String indent(int indent) { char[] blankArray = new char[indent]; Arrays.fill(blankArray, ' '); return new String(blankArray); } static private void println(PrintStream writer, int level, String txt) { writer.print(indent(INDENT * level)); writer.print(txt); writer.print(System.getProperty("line.separator")); } static private int levelForIndex(int index) { return index / INDENT; } } sdk/build-tools/org/opends/build/tools/Utilities.java
New file @@ -0,0 +1,159 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2008 Sun Microsystems, Inc. */ package org.opends.build.tools; import org.opends.messages.Message; import java.util.StringTokenizer; /** */ public class Utilities { /** * The end-of-line character for this platform. */ public static final String EOL = System.getProperty("line.separator"); /** * Inserts line breaks into the provided buffer to wrap text at no more than * the specified column width. Wrapping will only be done at space boundaries * and if there are no spaces within the specified width, then wrapping will * be performed at the first space after the specified column. * * @param text The text to be wrapped. * @param width The maximum number of characters to allow on a line if there * is a suitable breaking point. * * @return The wrapped text. */ public static String wrapText(String text, int width) { StringBuilder buffer = new StringBuilder(); StringTokenizer lineTokenizer = new StringTokenizer(text, "\r\n", true); while (lineTokenizer.hasMoreTokens()) { String line = lineTokenizer.nextToken(); if (line.equals("\r") || line.equals("\n")) { // It's an end-of-line character, so append it as-is. buffer.append(line); } else if (line.length() < width) { // The line fits in the specified width, so append it as-is. buffer.append(line); } else { // The line doesn't fit in the specified width, so it needs to be // wrapped. Do so at space boundaries. StringBuilder lineBuffer = new StringBuilder(); StringBuilder delimBuffer = new StringBuilder(); StringTokenizer wordTokenizer = new StringTokenizer(line, " ", true); while (wordTokenizer.hasMoreTokens()) { String word = wordTokenizer.nextToken(); if (word.equals(" ")) { // It's a space, so add it to the delim buffer only if the line // buffer is not empty. if (lineBuffer.length() > 0) { delimBuffer.append(word); } } else if (word.length() > width) { // This is a long word that can't be wrapped, so we'll just have to // make do. if (lineBuffer.length() > 0) { buffer.append(lineBuffer); buffer.append(EOL); lineBuffer = new StringBuilder(); } buffer.append(word); if (wordTokenizer.hasMoreTokens()) { // The next token must be a space, so remove it. If there are // still more tokens after that, then append an EOL. wordTokenizer.nextToken(); if (wordTokenizer.hasMoreTokens()) { buffer.append(EOL); } } if (delimBuffer.length() > 0) { delimBuffer = new StringBuilder(); } } else { // It's not a space, so see if we can fit it on the curent line. int newLineLength = lineBuffer.length() + delimBuffer.length() + word.length(); if (newLineLength < width) { // It does fit on the line, so add it. lineBuffer.append(delimBuffer).append(word); if (delimBuffer.length() > 0) { delimBuffer = new StringBuilder(); } } else { // It doesn't fit on the line, so end the current line and start // a new one. buffer.append(lineBuffer); buffer.append(EOL); lineBuffer = new StringBuilder(); lineBuffer.append(word); if (delimBuffer.length() > 0) { delimBuffer = new StringBuilder(); } } } } // If there's anything left in the line buffer, then add it to the // final buffer. buffer.append(lineBuffer); } } return buffer.toString(); } } sdk/build-tools/org/opends/build/tools/ValidJavaVersion.java
New file @@ -0,0 +1,68 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2008 Sun Microsystems, Inc. */ package org.opends.build.tools; import org.apache.tools.ant.taskdefs.condition.Condition; import org.apache.tools.ant.BuildException; /** * Ant condition to check whether we have a minimum required Java version. */ public class ValidJavaVersion implements Condition { // The minimum required Java version. String minVersion; /** * Set the minVersion attribute. * @param minVersion The minimum required Java version. */ public void setMinVersion(String minVersion) { this.minVersion = minVersion; } /** * Evaluate the condition. */ public boolean eval() throws BuildException { if (minVersion == null) { return true; } String version = System.getProperty("java.version"); if (version == null) { return false; } return version.compareTo(minVersion) >= 0; } } sdk/build-tools/org/opends/build/tools/package-info.java
New file @@ -0,0 +1,36 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2008 Sun Microsystems, Inc. */ /** * This package contains source for a number of tools that are used in some way * during the OpenDS build process. This includes custom Ant tasks, utilities * to format schema files, and to facilitate running server unit tests. */ package org.opends.build.tools;