| /******************************************************************************* |
| * Copyright (c) 2010 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.wtp.releng.fixups; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.FileReader; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.StringBufferInputStream; |
| import java.io.StringWriter; |
| import java.util.ArrayList; |
| import java.util.Properties; |
| |
| import org.eclipse.core.commands.ExecutionException; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.ui.console.ConsolePlugin; |
| import org.eclipse.ui.console.IConsole; |
| import org.eclipse.ui.console.IConsoleManager; |
| import org.eclipse.ui.console.MessageConsole; |
| import org.eclipse.ui.console.MessageConsoleStream; |
| |
| /** |
| * Simple tool to make features more consistent. Check license property is the |
| * standard value, and if not fixes that, and write new license.html file. |
| * |
| * @author davidw |
| * |
| */ |
| |
| public class CheckAndFixConsistency { |
| |
| |
| |
| private static final String LICENSE_KEY = "license="; |
| private static final String PLUGINID = "org.eclipse.wtp.releng.fixups"; |
| private static final String EOL = System.getProperty("line.separator", "\n"); |
| /* |
| * remember a slash '\' denotes continuation in a properties file, and the |
| * regex expression needs to escape that, so "\\", and to get in a string, |
| * each needs to be escaped, so that's why we need "\\\\" in continuation |
| * regex pattern |
| */ |
| private static final String CONTINUATION = "\\\\ *$"; |
| private static final String CONSOLE_NAME = "Releng Console"; |
| private static boolean DEBUG = false; |
| private String standardlicense = null; |
| private ArrayList featureProjects = new ArrayList(); |
| private ArrayList featureProjectsMissingProperties = new ArrayList(); |
| private ArrayList featureProjectsMissingLicense = new ArrayList(); |
| private ArrayList featuresModified = new ArrayList(); |
| private ArrayList featuresOkNotModified = new ArrayList(); |
| private ArrayList featuresCouldNotBeModified = new ArrayList(); |
| private int nFeatures; |
| private long starttime; |
| |
| public CheckAndFixConsistency() { |
| } |
| |
| /* |
| * lazy init instance variables that require IO, if not done yet. |
| */ |
| private void init() throws IOException { |
| if (standardlicense == null) { |
| InputStream propstream = null; |
| Properties standardproperties = new Properties(); |
| try { |
| propstream = this.getClass().getResourceAsStream("standard.properties"); |
| standardproperties.load(propstream); |
| standardlicense = standardproperties.getProperty("license"); |
| } |
| finally { |
| if (propstream != null) { |
| propstream.close(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * the command has been executed, so extract extract the needed |
| * information from the application context. |
| */ |
| public Object checkAndFixConsistency() throws ExecutionException { |
| |
| // assume return is ok, unless set otherwise. |
| Object returnobject = IStatus.OK; |
| starttime = System.currentTimeMillis(); |
| IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); |
| initCounterArrays(); |
| |
| for (int j = 0; j < projects.length; j++) { |
| IProject project = projects[j]; |
| IFile file = project.getFile("feature.xml"); |
| if ((file != null) && file.exists()) { |
| nFeatures++; |
| IFile propfile = project.getFile("feature.properties"); |
| if ((propfile != null) && propfile.exists()) { |
| featureProjects.add(project); |
| try { |
| fixup(propfile, project); |
| } |
| catch (IOException e) { |
| returnobject = new Status(0, PLUGINID, e.getMessage()); |
| } |
| catch (CoreException e) { |
| returnobject = new Status(0, PLUGINID, e.getMessage()); |
| } |
| } |
| else { |
| // we just save these for counting. Seems hard |
| // to easily know what is correct action, if any. |
| featureProjectsMissingProperties.add(project); |
| } |
| } |
| } |
| |
| reportSummaryOfResults(); |
| |
| |
| return returnobject; |
| } |
| |
| private void reportSummaryOfResults() { |
| MessageConsole myConsole = findConsole(CONSOLE_NAME); |
| MessageConsoleStream out = myConsole.newMessageStream(); |
| myConsole.activate(); |
| out.println(); |
| out.println("\tTotal number of features found: " + nFeatures); |
| out.println(); |
| report(out, featureProjectsMissingProperties, "The following feature(s) contained no feature.properties file"); |
| report(out, featureProjectsMissingLicense, "The following feature(s) contained no license property"); |
| report(out, featuresOkNotModified, "The following feature(s) were found ok, and not modified"); |
| report(out, featuresModified, "The following feature(s) were modified"); |
| report(out, featuresCouldNotBeModified, "The following feature(s) needed to be modified, but for some reason could not be"); |
| |
| out.println(); |
| long elapsedTime = System.currentTimeMillis() - starttime; |
| out.println("\tElapsed processing time : " + elapsedTime + " ms"); |
| out.println(); |
| } |
| |
| /* |
| * Make sure arrays are cleared, incase instance is ran more than once. |
| */ |
| private void initCounterArrays() { |
| featureProjects.clear(); |
| featureProjectsMissingProperties.clear(); |
| featureProjectsMissingLicense.clear(); |
| featuresModified.clear(); |
| featuresOkNotModified.clear(); |
| featuresCouldNotBeModified.clear(); |
| } |
| |
| private void fixup(IFile propfile, IProject project) throws IOException, CoreException { |
| |
| init(); |
| |
| Properties featureproperties = new Properties(); |
| featureproperties.load(propfile.getContents()); |
| String license = featureproperties.getProperty("license"); |
| if (license == null) { |
| featureProjectsMissingLicense.add(project); |
| } |
| else if (notequiv(license, standardlicense)) { |
| if (rewrite(propfile, project)) { |
| featuresModified.add(project); |
| // also, if we tweak license property, we'll blindly copy in |
| // new licesne.html file. |
| copyLicenseHtml(project); |
| } |
| else { |
| featuresCouldNotBeModified.add(project); |
| } |
| } |
| else { |
| featuresOkNotModified.add(project); |
| } |
| } |
| |
| private boolean rewrite(IFile propfile, IProject project) { |
| boolean result = false; |
| |
| /* |
| * We rewrite line by line to preserve existing comments and spaceing. |
| * The idea is to read and echo old one until we find "license=". At |
| * that point we read and echo from standard properties file (which is |
| * why its required that file contain only the exact license property |
| * we want). We skip old license property lines until we find a line |
| * that does not end in conttinuation character. Then, echo the rest |
| * of the old stuff. Remember, an "end of line" need not be platform's |
| * EOL, it could be any of \n, \r, \r\n, etc. Technically, what ever |
| * we find in use, is what we should rewite. (Not sure how "readline" |
| * works, on non-platform EOLs?). |
| */ |
| IFile featureProperties = project.getFile("feature.properties"); |
| InputStream standardInputStream = this.getClass().getResourceAsStream("standard.properties"); |
| BufferedReader br = null; |
| StringWriter bw = null; |
| try { |
| File featurePropertiesFile = new File(featureProperties.getLocationURI()); |
| br = new BufferedReader(new FileReader(featurePropertiesFile)); |
| |
| |
| bw = new StringWriter(); |
| |
| String oneline = null; |
| do { |
| oneline = br.readLine(); |
| if (oneline != null) { |
| if (oneline.startsWith(LICENSE_KEY)) { |
| // flush old input to end of property |
| while ((oneline != null) && oneline.matches(".*" + CONTINUATION)) { |
| oneline = br.readLine(); |
| } |
| |
| // Echo standard license property file |
| // The file much be exact segment we want for the |
| // property and end with an empty line. |
| while (standardInputStream.available() > 0) { |
| int onechar = standardInputStream.read(); |
| bw.write(onechar); |
| } |
| |
| } |
| else { |
| // echo old output to new file |
| // TODO: we should peek in old file and infer what |
| // EOL |
| // is already |
| // in use |
| bw.write(oneline + EOL); |
| } |
| } |
| } |
| |
| while (oneline != null); |
| closereader(br); |
| StringBufferInputStream newcontent = new StringBufferInputStream(bw.toString()); |
| featureProperties.setContents(newcontent, true, true, null); |
| // if we got through all that without exception, all is ok |
| result = true; |
| } |
| |
| catch (FileNotFoundException e) { |
| e.printStackTrace(); |
| result = false; |
| } |
| catch (IOException e) { |
| e.printStackTrace(); |
| result = false; |
| } |
| catch (CoreException e) { |
| e.printStackTrace(); |
| result = false; |
| } |
| finally { |
| closereader(br); |
| |
| if (standardInputStream != null) { |
| try { |
| standardInputStream.close(); |
| } |
| catch (IOException e) { |
| // weirdness |
| e.printStackTrace(); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| private void closereader(BufferedReader br) { |
| if (br != null) { |
| try { |
| br.close(); |
| } |
| catch (IOException e) { |
| // weirdness |
| e.printStackTrace(); |
| } |
| } |
| } |
| |
| private boolean copyLicenseHtml(IProject project) { |
| // in addition of features.properties, if we are re-writing it, we |
| // will blindly assume the license.html file also needs to be replaced |
| // with standard one. |
| boolean result = false; |
| IFile license = project.getFile("license.html"); |
| InputStream licenseStream = this.getClass().getResourceAsStream("license.html"); |
| try { |
| license.setContents(licenseStream, true, true, null); |
| result = true; |
| } |
| catch (CoreException e) { |
| e.printStackTrace(); |
| result = false; |
| } |
| finally { |
| if (licenseStream != null) { |
| try { |
| licenseStream.close(); |
| } |
| catch (IOException e) { |
| // weirdness |
| e.printStackTrace(); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| private boolean notequiv(String license, String standard) { |
| String licensecleaned = license.trim().replaceAll("\\s+", " "); |
| String standardcleaned = standard.trim().replaceAll("\\s+", " "); |
| |
| int diff = licensecleaned.compareTo(standardcleaned); |
| |
| if (DEBUG && (diff != 0)) { |
| System.out.println("difference compare result: " + diff); |
| } |
| return !(diff == 0); |
| |
| } |
| |
| |
| |
| private void report(MessageConsoleStream out, ArrayList tocheck, String message) { |
| |
| |
| |
| // IWorkbenchPage page = ...;//obtain the active page |
| // String id = IConsoleConstants.ID_CONSOLE_VIEW; |
| // IConsoleView view = (IConsoleView) page.showView(id); |
| // view.display(myConsole); |
| |
| |
| if ((tocheck != null) && (tocheck.size() > 0)) { |
| out.println(); |
| out.println("\t" + message); |
| out.println("\t\tCount: " + tocheck.size()); |
| for (Object object : tocheck) { |
| out.println("\t\t" + ((IProject) object).getName()); |
| } |
| out.println(); |
| } |
| } |
| |
| private MessageConsole findConsole(String name) { |
| |
| MessageConsole myConsole = null; |
| ConsolePlugin plugin = ConsolePlugin.getDefault(); |
| IConsoleManager conMan = plugin.getConsoleManager(); |
| IConsole[] existing = conMan.getConsoles(); |
| for (int i = 0; i < existing.length; i++) { |
| if (name.equals(existing[i].getName())) { |
| myConsole = (MessageConsole) existing[i]; |
| } |
| } |
| if (myConsole == null) { |
| // no console found, so create a new one |
| myConsole = new MessageConsole(name, null); |
| conMan.addConsoles(new IConsole[]{myConsole}); |
| } |
| |
| return myConsole; |
| } |
| |
| } |