blob: 04b096342a9066b88510290ebf9e300014822434 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006 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:
* Pascal Rapicault, IBM - Initial implementation
* David Williams, IBM, - added
* 'conservative' directive
* 'workpaceRoot' directive
* maintained some other attributes in pre-req'd bundles
* made output "ready to paste", if desired.
*
*******************************************************************************/
package org.eclipse.wtp.releng.tools.versionchecker;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import org.eclipse.core.runtime.IPlatformRunnable;
import org.eclipse.core.runtime.Platform;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.osgi.service.resolver.BundleSpecification;
import org.eclipse.osgi.service.resolver.VersionRange;
import org.osgi.framework.Version;
/**
* A simple, unsupported, little-tested utility to help convert from using
* unconstrained pre-req'd bundles, to ones constrained to be within a certain
* range.
*
* For example, if a plugin's manifest.mf file specifies
*
* <p>
* <code>Require-Bundle: org.eclipse.core.runtime</code>
* </p>
* <p>
* this utility will write
* </p>
* <p>
* <code>Require-Bundle: org.eclipse.core.runtime;bundle-version=&quot;[3.2.0,4.0.0)&quot;</code>
* </p>
* <p>
* or
* </p>
* <p>
* <code>Require-Bundle: org.eclipse.core.runtime;bundle-version=&quot;[3.2.0,3.3.0)&quot;</code>
* </p>
* <p>
* if <i>-conservative</i> is specified. In all case the lower bound is
* determined by the version found as this utility actually runs.
*
* </pre>
*
* <p>
* Directives:
* </p>
* <p>
* -filter "some regx expression"
* </p>
* <p>
* Will write/check manifest only for those plugins matching regx expression.
* </p>
* <p>
* -conservative
* </p>
* <p>
* Will increment 'minor' code, instead of 'major' code in upper bound of the
* range. This is required for those using another plugin's internal (non-API)
* methods, and recommended if you do not know for sure you are using
* API-only. The default is not-conservative, which increments the major
* field.
* </p>
* <p>
* -workspaceRoot "absolute file system path name to workspace"
* </p>
* <p>
* If specified, the manifest.mf files found in the workspace will be
* re-written with the results of this tool. Note. The workspace must "match"
* the runtime the tool is running in, for this to make any sense. The default
* is to simply write the recommended "Require-Bundle:" section the console
* log.
* </p>
* <p>
* Note: re-export visibility and optional resolution are maintained "as is"
* in output (but other pre-req settings (e.g. vendor?) may be lost. The
* intent is to provide "ready for pasting" content, if its happens to work
* well for your cases.
* </p>
* <p>
* Example invocation:
* </p>
* <p>
*
* <pre>
*
* java -jar startup.jar -clean -application
* org.eclipse.wtp.releng.versionchecker.dependencyChecker
*
* </pre>
*
* </p>
*
* <p>
* Example output:
* </p>
*
* <pre>
*
* bundle org.eclipse.wst.xml.core Require-Bundle:
* org.eclipse.core.runtime;bundle-version=&quot;[3.2.0,3.3.0)&quot;,
* org.eclipse.core.resources;bundle-version=&quot;[3.2.0,3.3.0)&quot;,
* org.eclipse.wst.common.uriresolver;bundle-version=&quot;[1.1.0,1.2.0)&quot;,
* org.eclipse.wst.sse.core;bundle-version=&quot;[1.1.0,1.2.0)&quot;,
* org.eclipse.text;bundle-version=&quot;[3.2.0,3.3.0)&quot;,
* org.eclipse.jem.util;resolution:=optional;bundle-version=&quot;[1.2.0,1.3.0)&quot;,
* org.eclipse.wst.validation;bundle-version=&quot;[1.1.0,1.2.0)&quot;,
* org.eclipse.emf.ecore.edit;resolution:=optional;bundle-version=&quot;[2.2.0,2.3.0)&quot;,
* org.eclipse.wst.common.emf;resolution:=optional;bundle-version=&quot;[1.1.0,1.2.0)&quot;,
* org.eclipse.emf.ecore.xmi;resolution:=optional;bundle-version=&quot;[2.2.0,2.3.0)&quot;,
* org.eclipse.wst.common.emfworkbench.integration;resolution:=optional;bundle-version=&quot;[1.1.0,1.2.0)&quot;,
* org.eclipse.wst.common.core;bundle-version=&quot;[1.1.0,1.2.0)&quot;,
* com.ibm.icu;bundle-version=&quot;[3.4.4,3.5.0)&quot;,
* org.apache.xerces;visibility:=reexport;bundle-version=&quot;[2.8.0,2.9.0)&quot;
*
* </pre>
*/
public class DependencyChecker implements IPlatformRunnable {
private static final String CONSERVATIVE_DIRECTIVE = "-conservative";
private static final String FILTER_DIRECTIVE = "-filter";
private static final String WORKSPACEROOT_DIRECTIVE = "-workspaceRoot";
private static final String REQUIRE_BUNDLE = "Require-Bundle:";
private static final String EOL = System.getProperty("line.separator");
private boolean conservative = false;
private String workspaceroot;
public DependencyChecker() {
}
public Object run(Object o) throws Exception {
String args[] = Platform.getApplicationArgs();
String filter = null;
for (int nArgs = 0; nArgs < args.length; nArgs++) {
if (args[nArgs].equals(FILTER_DIRECTIVE) && (nArgs + 1 < args.length))
filter = args[nArgs + 1];
else if (args[nArgs].equals(CONSERVATIVE_DIRECTIVE)) {
conservative = true;
}
else if (args[nArgs].equals(WORKSPACEROOT_DIRECTIVE) && (nArgs + 1 < args.length))
workspaceroot = args[nArgs + 1];
}
BundleDescription bundles[] = Platform.getPlatformAdmin().getState().getBundles();
for (int i = 0; i < bundles.length; i++) {
String bundleName = bundles[i].getSymbolicName();
if ((filter == null) || bundleName.matches(filter)) {
BundleSpecification req[] = bundles[i].getRequiredBundles();
ArrayList bundleSpecStrings = new ArrayList();
for (int j = 0; j < req.length; j++) {
BundleSpecification currentBundle = req[j];
VersionRange specifiedRange = currentBundle.getVersionRange();
if (specifiedRange == VersionRange.emptyRange) {
BundleDescription required = Platform.getPlatformAdmin().getState().getBundle(currentBundle.getName(), null);
if (required != null) {
Version reqVersion = required.getVersion();
Version minVersion = new Version(reqVersion.getMajor(), reqVersion.getMinor(), reqVersion.getMicro());
Version maxVersion = null;
if (conservative) {
maxVersion = new Version(minVersion.getMajor(), minVersion.getMinor() + 1, 0);
}
else {
maxVersion = new Version(minVersion.getMajor() + 1, 0, 0);
}
String name = currentBundle.getName();
String exported = "";
if (currentBundle.isExported()) {
exported = ";visibility:=reexport";
}
String optional = "";
if (currentBundle.isOptional()) {
exported = ";resolution:=optional";
}
String requiredRange = ";bundle-version=\"" + new VersionRange(minVersion, true, maxVersion, false) + "\"";
String spec = new String(" " + name + exported + optional + requiredRange);
bundleSpecStrings.add(spec);
}
}
}
// print
if (bundleSpecStrings.size() > 0) {
// header
System.out.println();
System.out.println("bundle " + bundleName);
StringBuffer sb = formStringBuffer(bundleSpecStrings);
System.out.println(sb);
if (workspaceroot != null) {
rewriteManifest(bundleName, sb);
}
}
}
}
return IPlatformRunnable.EXIT_OK;
}
private void rewriteManifest(String bundleName, StringBuffer sb) throws IOException {
try {
Reader reader = new FileReader(workspaceroot + bundleName + "/META-INF/MANIFEST.MF");
BufferedReader bufferedReader = new BufferedReader(reader);
ArrayList initialLines = new ArrayList();
ArrayList finalLines = new ArrayList();
String inline = null;
inline = bufferedReader.readLine();
while ((inline != null) && (!(inline.startsWith(REQUIRE_BUNDLE)))) {
initialLines.add(new String(inline));
inline = bufferedReader.readLine();
}
if (inline != null) {
inline = bufferedReader.readLine();
while (((inline != null) && (inline.startsWith(" ")))) {
inline = bufferedReader.readLine();
}
}
while (inline != null) {
finalLines.add(new String(inline));
inline = bufferedReader.readLine();
}
bufferedReader.close();
Writer writer = new FileWriter(workspaceroot + bundleName + "/META-INF/MANIFEST.MF");
BufferedWriter bufferedWriter = new BufferedWriter(writer);
for (int lines = 0; lines < initialLines.size(); lines++) {
bufferedWriter.write(initialLines.get(lines) + EOL);
}
bufferedWriter.write(sb.toString());
for (int lines = 0; lines < finalLines.size(); lines++) {
bufferedWriter.write(finalLines.get(lines) + EOL);
}
bufferedWriter.close();
}
catch (FileNotFoundException e) {
// if no manifest file, ignore, there's nothing to re-write
}
}
private StringBuffer formStringBuffer(ArrayList bundleSpecStrings) {
StringBuffer sb = new StringBuffer();
// spec section (note, print only, no EOL, no space)
sb.append(REQUIRE_BUNDLE);
for (int k = 0; k < bundleSpecStrings.size(); k++) {
sb.append(bundleSpecStrings.get(k));
String COMMA = "";
if (k < bundleSpecStrings.size() - 1) {
COMMA = ",";
}
sb.append(COMMA + EOL);
}
return sb;
}
}