blob: fdc14b0a62b8ef5d8a4ba9c7459f9b1d06fab788 [file] [log] [blame]
/*******************************************************************************
* 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;
}
}