| /******************************************************************************* |
| * Copyright (c) 2010, 2017 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.equinox.p2.tests; |
| |
| import java.io.*; |
| import java.util.*; |
| import org.osgi.framework.Version; |
| |
| /* |
| * Class which can generate features and bundles for test data. |
| * See #printUsage for arguments. |
| */ |
| public class GenerateTestData { |
| |
| static final String baseBundleName = "My Bundle"; |
| static final String baseBundleId = "com.example.bundle"; |
| static final Version bundleVersion = new Version("1.0"); |
| |
| static final String baseFeatureName = "My feature"; |
| static final String baseFeatureId = "com.example.feature"; |
| static final Version featureVersion = new Version("1.0"); |
| |
| static int numFeatures = 0; |
| static int numBundles = 0; |
| static int numRequires = 0; |
| static File outputFile = null; |
| static Random random = new Random(System.currentTimeMillis()); |
| |
| Set<TestFeature> features = new HashSet<>(); |
| List<TestBundle> bundles = new ArrayList<>(); |
| |
| /* |
| * Abstract class representing a feature or a bundle. |
| */ |
| static abstract class TestObject { |
| String name; |
| String id; |
| Version version; |
| // use a set to avoid duplicates |
| Set<TestObject> requires = new HashSet<>(); |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (!(obj instanceof TestBundle)) |
| return false; |
| TestBundle other = (TestBundle) obj; |
| return id.equals(other.id) && version.equals(other.version); |
| } |
| |
| @Override |
| public int hashCode() { |
| return id.hashCode() + version.hashCode(); |
| } |
| |
| // subclasses override to write out feature.xml or manifest.mf |
| abstract String getManifest(); |
| } |
| |
| static class TestBundle extends TestObject { |
| |
| @Override |
| String getManifest() { |
| StringBuilder manifest = new StringBuilder(); |
| manifest.append("Manifest-Version: 1.0\n"); |
| manifest.append("Bundle-RequiredExecutionEnvironment: J2SE-1.4\n"); |
| manifest.append("Bundle-ManifestVersion: 2\n"); |
| manifest.append("Bundle-Name: " + name + '\n'); |
| manifest.append("Bundle-SymbolicName: " + id + '\n'); |
| manifest.append("Bundle-Version: " + version + '\n'); |
| if (!requires.isEmpty()) { |
| StringBuilder buffer = new StringBuilder(); |
| buffer.append("Require-Bundle: "); |
| for (Iterator<TestObject> iter = requires.iterator(); iter.hasNext();) { |
| TestObject req = iter.next(); |
| buffer.append(req.id); |
| if (iter.hasNext()) |
| buffer.append(",\n "); |
| } |
| manifest.append(buffer.toString()); |
| } |
| return manifest.toString(); |
| } |
| |
| } |
| |
| static class TestFeature extends TestObject { |
| |
| @Override |
| String getManifest() { |
| StringBuilder buffer = new StringBuilder(); |
| buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); |
| buffer.append(" <feature\n"); |
| buffer.append("\t\tid=\"" + id + "\"\n"); |
| buffer.append("\t\tlabel=\"" + name + "\"\n"); |
| buffer.append("\t\tversion=\"" + version + "\"\n"); |
| buffer.append("\t\tprovider-name=\"providerName\"\n"); |
| buffer.append("\t\timage=\"eclipse_update_120.jpg\">\n"); |
| buffer.append("\t<description>\n"); |
| buffer.append("\t\tdescription\n"); |
| buffer.append("\t</description>\n"); |
| buffer.append("\t<copyright>\n"); |
| buffer.append("\t\tcopyright\n"); |
| buffer.append("\t</copyright>\n"); |
| buffer.append("\t<license url=\"licenseURL\">\n"); |
| buffer.append("\t\tlicense\n"); |
| buffer.append("\t</license>\n"); |
| for (TestObject bundle : requires) { |
| buffer.append("\t<plugin\n"); |
| buffer.append("\t\tid=\"" + bundle.id + "\"\n"); |
| buffer.append("\t\tdownload-size=\"0\"\n"); |
| buffer.append("\t\tinstall-size=\"0\"\n"); |
| buffer.append("\t\tversion=\"" + bundle.version + "\"/>\n"); |
| } |
| buffer.append("</feature>\n"); |
| return buffer.toString(); |
| } |
| } |
| |
| public static void main(String[] args) throws IOException { |
| processCommandLineArgs(args); |
| if (!validate()) { |
| printUsage(); |
| return; |
| } |
| new GenerateTestData().generate(); |
| } |
| |
| static void printUsage() { |
| StringBuilder buffer = new StringBuilder(); |
| buffer.append("\nUse this application to generate test feature and bundle data.\n"); |
| buffer.append("Parameters:\n"); |
| buffer.append("-output <location>\n"); |
| buffer.append("-features <number of features>\n"); |
| buffer.append("-bundles <number of bundles>\n"); |
| buffer.append("-requires <max number of requires for each bundle> [optional]\n"); |
| buffer.append("\tSpecifying a requires of X bundles picks up to X of previously created bundles to be required.\n"); |
| buffer.append("\tThis means bundles produced at the end are more likely to have X requirements.\n"); |
| buffer.append("\tThis is done to avoid circular dependencies.\n"); |
| System.err.println(buffer.toString()); |
| } |
| |
| /* |
| * Verify setup before starting. Ensure all required parameters have been set. |
| */ |
| static boolean validate() { |
| StringBuilder buffer = new StringBuilder(); |
| if (outputFile == null) |
| buffer.append("Need to set an output directory.\n"); |
| if (numFeatures < 0 || numBundles <= 0) |
| buffer.append("Need to specifiy at least one bundle.\n"); |
| if (numFeatures > numBundles) |
| buffer.append("Number of features must be the same or less than the number of bundles.\n"); |
| if (numRequires > numBundles - 1) |
| buffer.append("Cannot have more required bundles than bundles.\n"); |
| if (buffer.length() == 0) |
| return true; |
| System.err.println(buffer.toString()); |
| return false; |
| } |
| |
| static void processCommandLineArgs(String[] args) { |
| for (int i = 0; i < args.length - 1; i++) { |
| String arg = args[i]; |
| String next = args[++i]; |
| if ("-features".equalsIgnoreCase(arg)) { |
| numFeatures = Integer.parseInt(next); |
| } else if ("-bundles".equalsIgnoreCase(arg) || "-plugins".equalsIgnoreCase(arg)) { |
| numBundles = Integer.parseInt(next); |
| } else if ("-requires".equalsIgnoreCase(arg)) { |
| numRequires = Integer.parseInt(next); |
| } else if ("-output".equalsIgnoreCase(arg)) { |
| outputFile = new File(next); |
| } |
| } |
| } |
| |
| void generate() throws IOException { |
| System.out.println("Generating " + numBundles + " bundles."); |
| for (int i = 0; i < numBundles; i++) { |
| TestBundle bundle = generateBundle(baseBundleName + i, baseBundleId + i, bundleVersion); |
| bundles.add(bundle); |
| } |
| |
| System.out.println("Generating " + numFeatures + " features."); |
| for (int i = 0; i < numFeatures; i++) { |
| TestFeature feature = generateFeature(baseFeatureName + i, baseFeatureId + i, featureVersion, i); |
| features.add(feature); |
| } |
| |
| save(); |
| } |
| |
| /* |
| * Persist the features and bundles to disk. |
| */ |
| void save() throws IOException { |
| outputFile.mkdirs(); |
| File featuresDir = new File(outputFile, "features"); |
| featuresDir.mkdirs(); |
| File pluginsDir = new File(outputFile, "plugins"); |
| pluginsDir.mkdirs(); |
| |
| System.out.println("Writing " + features.size() + " features."); |
| for (TestFeature feature : features) { |
| File featureDir = new File(featuresDir, feature.id + '_' + feature.version); |
| File location = new File(featureDir, "feature.xml"); |
| write(location, feature.getManifest()); |
| } |
| |
| System.out.println("Writing " + bundles.size() + " bundles."); |
| for (TestBundle bundle : bundles) { |
| File pluginDir = new File(pluginsDir, bundle.id + '_' + bundle.version); |
| File location = new File(new File(pluginDir, "META-INF"), "MANIFEST.MF"); |
| write(location, bundle.getManifest()); |
| } |
| } |
| |
| void write(File location, String data) throws IOException { |
| File parent = location.getParentFile(); |
| if (parent == null) |
| throw new RuntimeException("Unable to write to: " + location.getAbsolutePath() + "due to null parent."); |
| parent.mkdirs(); |
| try (OutputStream output = new BufferedOutputStream(new FileOutputStream(location))) { |
| output.write(data.getBytes()); |
| } |
| } |
| |
| // Return a random bundle from the collection of already produced ones. |
| TestBundle getRandomBundle() { |
| if (bundles.isEmpty()) |
| return null; |
| int index = random.nextInt(bundles.size()); |
| return bundles.get(index); |
| } |
| |
| TestBundle generateBundle(String name, String id, Version version) { |
| TestBundle bundle = new TestBundle(); |
| bundle.id = id; |
| bundle.name = name; |
| bundle.version = version; |
| for (int i = 0; i < numRequires; i++) { |
| TestBundle req = getRandomBundle(); |
| if (req != null) |
| bundle.requires.add(req); |
| } |
| return bundle; |
| } |
| |
| TestFeature generateFeature(String name, String id, Version version, int index) { |
| TestFeature feature = new TestFeature(); |
| feature.id = id; |
| feature.name = name; |
| feature.version = version; |
| // bundles were generated first and we already checked that we have more/equal bundles and features |
| // so we should be ok here. |
| TestBundle bundle = bundles.get(index); |
| if (bundle == null) |
| throw new RuntimeException("Could not find bundle at index: " + index + " to match feature: " + id); |
| feature.requires.add(bundle); |
| return feature; |
| } |
| |
| } |