| /* |
| |
| Derby - Class SetDerbyVersion |
| |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| |
| */ |
| |
| import java.io.BufferedReader; |
| import java.io.BufferedWriter; |
| import java.io.EOFException; |
| import java.io.File; |
| import java.io.FileReader; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.net.URL; |
| import java.net.URLClassLoader; |
| import java.sql.Connection; |
| import java.sql.DatabaseMetaData; |
| import java.sql.Driver; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * Checks the current Derby jars in the source tree directory, obtains the |
| * Derby version from them, and replaces the value of the placeholder |
| * version tags in the POM files. |
| * <p> |
| * After this method has been successfully run you should be ready to |
| * generate the Maven 2 artifacts for Derby. |
| * <p> |
| * The main task of this class is to replace the version tags in the Maven |
| * POM files. The can be done manually, but exact process would vary from |
| * platform to platform. Also, running a search-and-replace could potentially |
| * replace tags not supposed to be replaced. To make the Maven 2 artifact |
| * publish process simpler, this class was written. |
| */ |
| //@NotThreadSafe |
| public class SetDerbyVersion { |
| |
| private static final String PROMPT_CONT_WARN = |
| "Do you want to continue despite the warnings?"; |
| private static final String PROMPT_USE_SANE = |
| "Do you want to generate artifacts with SANE jars?"; |
| private static final String JDBC_URL = |
| "jdbc:derby:memory:testDB;create=true"; |
| private static final String REL_JAR_PATH = "../jars"; |
| private static final File SANE = new File(REL_JAR_PATH, "sane"); |
| private static final File INSANE = new File(REL_JAR_PATH, "insane"); |
| /** List of required jar files the Maven 2 Derby artifacts. */ |
| private static final String[] JARS = new String[] { |
| "derby.jar", |
| "derby.war", |
| "derbynet.jar", |
| "derbyclient.jar", |
| "derbytools.jar", |
| "derbyoptionaltools.jar", |
| // Ignore derbyTesting.jar, not part of the Maven 2 artifacts. |
| // "derbyTesting.jar", |
| // Ignore derbyrun.jar, not part of the Maven 2 artifacts. |
| //"derbyrun.jar", |
| // The various locale files. |
| "derbyLocale_cs.jar", |
| "derbyLocale_de_DE.jar", |
| "derbyLocale_es.jar", |
| "derbyLocale_fr.jar", |
| "derbyLocale_hu.jar", |
| "derbyLocale_it.jar", |
| "derbyLocale_ja_JP.jar", |
| "derbyLocale_ko_KR.jar", |
| "derbyLocale_pl.jar", |
| "derbyLocale_pt_BR.jar", |
| "derbyLocale_ru.jar", |
| "derbyLocale_zh_CN.jar", |
| "derbyLocale_zh_TW.jar", |
| }; |
| |
| /** |
| * Displays a prompt and obtains a yes / no answer from standard in. |
| * |
| * @param prompt the prompt to display |
| * @return {@code true} if the answer is yes, {@code false} if the answer |
| * is no. |
| * @throws IOException if reading from standard in fails |
| */ |
| private static boolean getYesNoInput(String prompt) |
| throws IOException { |
| // We don't care about keeping the objects around, this method will |
| // only be used a few times. |
| BufferedReader bIn = new BufferedReader( |
| new InputStreamReader(System.in)); |
| while (true) { |
| System.out.print(">> " + prompt + " (yes/no) "); |
| String answer = bIn.readLine(); |
| if (answer == null) { |
| // We don't know what do to here, so just fail. |
| throw new EOFException("Input stream closed."); |
| } |
| if (answer.equals("yes")) { |
| return true; |
| } else if (answer.equals("no")) { |
| return false; |
| } |
| } |
| } |
| |
| /** |
| * Set to {@code true} if a warning message is printed. Must be manually |
| * reset if used to check for warnings in a part of the code. |
| */ |
| private boolean warnings = false; |
| /** The version string inserted into the POMs. */ |
| private String versionString = "ALPHA_VERSION"; |
| private File PREFIX; |
| |
| /** |
| * Prints a warning message and sets the internal warning flag. |
| * |
| * @param msg the message to print |
| */ |
| private void warn(String msg) { |
| warnings = true; |
| System.out.println("WARNING! " + msg); |
| } |
| |
| private void info(String msg) { |
| System.out.println(msg); |
| } |
| |
| /** |
| * Checks that all required jars are found in the jar directory. |
| * |
| * @return {@code true} if all required jars exist, {@code false} otherwise. |
| */ |
| public boolean checkJars() |
| throws Exception { |
| if (!SANE.exists() && !INSANE.exists()) { |
| warn("No jars exist. Produce a Derby release build."); |
| return false; |
| } |
| if (SANE.exists() && INSANE.exists()) { |
| warn("Both SANE and INSANE jars exist."); |
| return false; |
| } |
| PREFIX = SANE.exists() ? SANE : INSANE; |
| if (SANE.exists()) { |
| warn("Only SANE jars exist. Normally INSANE jars are used for a " + |
| "release."); |
| boolean answer = getYesNoInput(PROMPT_USE_SANE); |
| if (!answer) { |
| return false; |
| } |
| } |
| URL[] URLS = new URL[JARS.length]; |
| for (int i=0; i < JARS.length; i++) { |
| URLS[i] = new File(PREFIX, JARS[i]).toURI().toURL(); |
| } |
| |
| warnings = false; // Reuse the warnings flag. |
| // Make sure the files are there. |
| for (URL url : URLS) { |
| File f = new File(url.toURI()); |
| info(String.format( |
| "Checking file: %-30s %,12d bytes", |
| f.getName(), f.length())); |
| if (!f.exists()) { |
| warn("Missing file: " + f.getCanonicalPath()); |
| } else if (f.length() == 0) { |
| warn("Empty file: " + f.getCanonicalPath()); |
| } |
| } |
| info(""); |
| if (warnings) { |
| // Fail here. |
| warn("There are missing or empty jar files."); |
| return false; |
| } |
| |
| // The class loader used for the Derby jars. |
| URLClassLoader cl = new URLClassLoader(URLS, null); |
| |
| // Extra sanity check for the sanity... |
| try { |
| Class.forName( |
| "org.apache.derby.shared.common.sanity.SanityManager", |
| true ,cl); |
| if (PREFIX == INSANE) { |
| warn("Found SanityManager in INSANE build. Aborting."); |
| return false; |
| } |
| } catch (ClassNotFoundException cnfe) { |
| if (PREFIX == SANE) { |
| warn("Unable to load SanityManager in SANE build. Aborting."); |
| return false; |
| } |
| } |
| |
| // Fire up Derby to get the version string. |
| Class driverClass = |
| Class.forName("org.apache.derby.jdbc.EmbeddedDriver", true, cl); |
| Driver driver = (Driver)driverClass.newInstance(); |
| Connection con = driver.connect(JDBC_URL, null); |
| DatabaseMetaData meta = con.getMetaData(); |
| con.close(); |
| // Delete the derby.log file. |
| new File("derby.log").delete(); |
| |
| // I.e.: 10.6.0.0 alpha - (882129M) |
| String fullVersion = meta.getDatabaseProductVersion(); |
| String[] components = fullVersion.split(" - "); |
| versionString = components[0].replaceAll(" ", "_"); |
| String srcRevision = components[1].replaceAll("\\(|\\)", ""); |
| info("Obtained product version string: " + fullVersion); |
| info("(version=" + versionString + ", revision=" + srcRevision + ")"); |
| if (versionString.contains("beta")) { |
| warn("This is a BETA build."); |
| } |
| if (versionString.contains("alpha")) { |
| warn("This is an ALPHA build."); |
| } |
| if (srcRevision.endsWith("M")) { |
| warn("The sources had been modified when the jars were built."); |
| warnings = true; |
| } |
| if (warnings) { |
| if (!getYesNoInput(PROMPT_CONT_WARN)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Replaces the relevant version tags in the various POM files. |
| * |
| * @throws IOException if accessing a POM file fails |
| */ |
| public boolean setPOMVersionTags() |
| throws IOException { |
| File curDir = new File("."); |
| boolean gotWarnings = false; |
| // We only descend one level, no need for a recursive method. |
| for (File topLevel : curDir.listFiles()) { |
| if (topLevel.getName().equals("pom.xml")) { |
| gotWarnings |= setVersionTag(topLevel); |
| } |
| if (topLevel.isDirectory()) { |
| for (File l1 : topLevel.listFiles()) { |
| if (l1.getName().equals("pom.xml")) { |
| gotWarnings |= setVersionTag(l1); |
| // There is only one POM in each sub-directory. |
| break; |
| } |
| } |
| } |
| } |
| |
| // See if we ran into problems when replacing the version tags. |
| info(""); |
| if (gotWarnings) { |
| warn("There were errors replacing the POM version tags."); |
| } else { |
| info("POM version tags replacement succeeded."); |
| info("It is recommended that you verify the POM diffs " + |
| "before running Maven."); |
| } |
| return (warnings == false); |
| } |
| |
| public void printSanityNote() |
| throws IOException { |
| if (PREFIX == SANE) { |
| info(""); |
| info("NOTE: Remember to change the <sanity> tag in the top-level"); |
| info(" POM, setting it to 'sane'."); |
| } |
| } |
| |
| /** |
| * Verifies that the correct number of tags were replaced in the POM. |
| * |
| * @param replaceCount the number of tags replaced |
| * @param pom the POM modified |
| * @return {@code 0} if the check passed, a negative value if too few tags |
| * were replaced, and a positive value if too many tags were replaced. |
| */ |
| private int checkResult(int replaceCount, File pom) { |
| // The locales requires two replacements, due to the dependency. |
| String parent = pom.getParent(); |
| if (parent.contains("derbyLocale")) { |
| return (replaceCount - 2); |
| // derbynet also requries two replacements (derby.jar dependency) |
| } else if (parent.contains("net")) { |
| return (replaceCount - 2); |
| } else { |
| return (replaceCount - 1); |
| } |
| } |
| |
| /** |
| * Replaces all qualifying version tags in the specified POM. |
| * |
| * @param pom the POM to modify |
| * @return {@code false} if warnings were produced when replacing, |
| * {@code true} if all seemed to go well. |
| * |
| * @throws IOException if reading or writing to the POM file fails |
| */ |
| private boolean setVersionTag(File pom) |
| throws IOException { |
| // Clear internal warning flag. |
| warnings = false; |
| // Just read the whole file into memory. |
| List<String> lines = readFile(pom); |
| |
| // Start writing the file back out, and search for tags to replace. |
| BufferedWriter bOut = new BufferedWriter(new FileWriter(pom, false)); |
| int replaced = 0; |
| boolean artifactIdOk = false; |
| boolean groupIdOk = false; |
| // Could have used XML, but keep it simple. |
| // artifactId and groupId are used to qualify the version tag, as it can |
| // be used in more places than those we want to replace. |
| for (String line : lines) { |
| // Look for tags for qualification. |
| if (line.trim().startsWith("<artifactId>") && |
| line.contains("derby")) { |
| artifactIdOk = true; |
| } else if (line.trim().startsWith("<groupId>") && |
| line.contains("org.apache.derby")) { |
| groupIdOk = true; |
| } |
| |
| // Change line if a qualified version tag, echo otherwise. |
| if (line.trim().startsWith("<version>") && |
| artifactIdOk && groupIdOk) { |
| // Replace tag. |
| int whitespaceTag = line.indexOf(">"); |
| bOut.write(line.substring(0, whitespaceTag +1)); |
| bOut.write(versionString); |
| int tagEnd = line.indexOf("<", whitespaceTag); |
| bOut.write(line.substring(tagEnd)); |
| bOut.newLine(); |
| replaced++; |
| artifactIdOk = groupIdOk = false; |
| } else { |
| bOut.write(line); |
| bOut.newLine(); |
| } |
| } |
| try { |
| bOut.flush(); |
| bOut.close(); |
| } catch (IOException ioe) { |
| warn("Flushing/closing stream for " + pom.getCanonicalPath() + |
| " failed: " + ioe.getMessage()); |
| } |
| int result = checkResult(replaced, pom); |
| if (result == 0) { |
| info("Replaced " + replaced + " version tag(s) in " + |
| pom.getParentFile().getName() + "/" + pom.getName()); |
| } else if (result > 0) { |
| warn("Too many version tags (" + replaced + " > " + |
| (replaced - result) + ") replaced in " + pom.getPath()); |
| } else { |
| warn("Too few version tags (" + replaced + " < " + |
| (replaced - result) + ") replaced in " + pom.getPath()); |
| } |
| return warnings; |
| } |
| |
| /** |
| * Reads the contents of a text file. |
| * |
| * @param f the file to read |
| * @return A list containing the lines of the file. |
| * @throws IOException if reading the file fails |
| */ |
| private List<String> readFile(File f) |
| throws IOException { |
| ArrayList<String> lines = new ArrayList<String>(); |
| BufferedReader bIn = new BufferedReader(new FileReader(f)); |
| String lineIn; |
| try { |
| while ((lineIn = bIn.readLine()) != null) { |
| lines.add(lineIn); |
| } |
| } finally { |
| try { |
| bIn.close(); |
| } catch (IOException ioe) { |
| // Just print a warning. |
| warn("Failed to close input stream for " + f.getPath() + ": " + |
| ioe.getMessage()); |
| } |
| } |
| return lines; |
| } |
| |
| /** |
| * Quits the JVM if a failure is detected. |
| * |
| * @param success the return value to check |
| */ |
| private static void ensureSuccess(boolean success) { |
| if (!success) { |
| System.out.println(); |
| System.out.println( |
| "!! The process failed or was aborted by the user."); |
| System.out.println( |
| " Read the above output and take corrective measures."); |
| System.exit(1); |
| } |
| } |
| |
| /** |
| * Checks the current Derby jars in the source tree directory, obtains the |
| * Derby version from them, and replaces the value of the placeholder |
| * version tags in the POM files. |
| * <p> |
| * After this method has been successfully run you should be ready to |
| * generate the Maven 2 artifacts for Derby. |
| * |
| * @param args ignored |
| * @throws Exception if something goes wrong |
| */ |
| public static void main(String[] args) |
| throws Exception { |
| SetDerbyVersion sdv = new SetDerbyVersion(); |
| ensureSuccess(sdv.checkJars()); |
| ensureSuccess(sdv.setPOMVersionTags()); |
| sdv.printSanityNote(); |
| } |
| } |