1 /*******************************************************************************
2  * Copyright (c) 2009, 2017 IBM Corporation and others.
3  * All rights reserved.
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License 2.0 which accompanies this distribution,
6  * and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  * IBM Corporation - initial implementation and ideas
13  * Sonatype Inc. - trim down for annotation work
14  ******************************************************************************/
15 
16 package org.eclipse.equinox.p2.tests;
17 
18 import java.io.*;
19 import java.util.*;
20 import org.eclipse.equinox.internal.p2.metadata.*;
21 import org.eclipse.equinox.p2.metadata.*;
22 import org.eclipse.equinox.p2.metadata.MetadataFactory.InstallableUnitDescription;
23 
24 public class ReducedCUDFParser {
25 
26 	private static final boolean DEBUG = false; //TO SET TO FALSE FOR COMPETITION
27 	private static final boolean TIMING = true; //TO SET TO FALSE FOR COMPETITION
28 	private InstallableUnitDescription currentIU = null;
29 	//	private ProfileChangeRequest currentRequest = null;
30 	private List<IInstallableUnit> allIUs = new ArrayList<>();
31 	//	private QueryableArray query = null;
32 
33 	class Tuple {
34 		String name;
35 		String version;
36 		String operator;
37 
Tuple(String line)38 		Tuple(String line) {
39 			String[] tuple = new String[3];
40 			int i = 0;
41 			for (StringTokenizer iter = new StringTokenizer(line, " \t"); iter.hasMoreTokens(); i++)
42 				tuple[i] = iter.nextToken().trim();
43 			name = tuple[0];
44 			operator = tuple[1];
45 			version = tuple[2];
46 		}
47 	}
48 
49 	//
50 	//	public ProfileChangeRequest parse(File file) {
51 	//		return parse(file, false, null);
52 	//	}
53 	//
54 	//	public ProfileChangeRequest parse(File file, boolean includeRecommends, String sumProperty) {
55 	//		try {
56 	//			return parse(new FileInputStream(file), includeRecommends, sumProperty);
57 	//		} catch (FileNotFoundException e) {
58 	//			e.printStackTrace();
59 	//			return null;
60 	//		}
61 	//	}
62 	//
63 	//	public ProfileChangeRequest parse(InputStream stream) {
64 	//		return parse(stream, false, null);
65 	//	}
66 	//
67 	//	public ProfileChangeRequest parse(InputStream stream, String sumProperty) {
68 	//		return parse(stream, false, sumProperty);
69 	//	}
70 
parse(InputStream stream, boolean includeRecommends, String sumProperty)71 	public void parse(InputStream stream, boolean includeRecommends, String sumProperty) {
72 		BufferedReader reader = null;
73 		try {
74 			reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
75 			String next = reader.readLine();
76 			while (true) {
77 
78 				// look-ahead to check for line continuation
79 				String line = next;
80 				for (next = reader.readLine(); next != null && next.length() > 1 && next.charAt(0) == ' '; next = reader.readLine()) {
81 					line = line + next.substring(1);
82 				}
83 
84 				// terminating condition of the loop... reached the end of the file
85 				if (line == null) {
86 					validateAndAddIU();
87 					break;
88 				}
89 
90 				// end of stanza
91 				if (line.trim().length() == 0) {
92 					validateAndAddIU();
93 					continue;
94 				}
95 
96 				// preamble stanza
97 				if (line.startsWith("#") || line.startsWith("preamble: ") || line.startsWith("property: ") || line.startsWith("univ-checksum: ")) {
98 					// ignore
99 				}
100 
101 				//				// request stanza
102 				//				else if (line.startsWith("request: ")) {
103 				//					handleRequest(line);
104 				//				} else if (line.startsWith("install: ")) {
105 				//					handleInstall(line);
106 				//				} else if (line.startsWith("upgrade: ")) {
107 				//					handleUpgrade(line);
108 				//				} else if (line.startsWith("remove: ")) {
109 				//					handleRemove(line);
110 				//				}
111 
112 				// package stanza
113 				else if (line.startsWith("package: ")) {
114 					handlePackage(line);
115 				} else if (line.startsWith("version: ")) {
116 					handleVersion(line);
117 					//				} else if (line.startsWith("installed: ")) {
118 					//					handleInstalled(line);
119 				} else if (line.startsWith("depends: ")) {
120 					handleDepends(line);
121 					//				} else if (line.startsWith("conflicts: ")) {
122 					//					handleConflicts(line);
123 				} else if (line.startsWith("provides: ")) {
124 					handleProvides(line);
125 				} else if (line.startsWith("singleton:")) {
126 					handleSingleton(line);
127 				}
128 				//				} else if (line.startsWith("expected: ")) {
129 				//					handleExpected(line);
130 				//				} else if (line.startsWith("recommends: ") && includeRecommends) {
131 				//					handleRecommends(line);
132 				//				} else if (line.startsWith("keep: ")) {
133 				//					handleKeep(line);
134 				//				} else if (sumProperty != null && line.startsWith(sumProperty + ":")) {
135 				//					handleSumProperty(line, sumProperty);
136 				//				}
137 			}
138 		} catch (FileNotFoundException e) {
139 			e.printStackTrace();
140 		} catch (IOException e) {
141 			e.printStackTrace();
142 		} finally {
143 			if (reader != null)
144 				try {
145 					reader.close();
146 				} catch (IOException e) {
147 					// ignore
148 				}
149 		}
150 		if (TIMING)
151 			//			Log.println("Time to parse:" + (System.currentTimeMillis() - start));
152 			if (DEBUG)
153 				for (IInstallableUnit iu : allIUs)
154 					debug((InstallableUnit) iu);
155 		//		if (FORCE_QUERY) {
156 		//			if (query == null)
157 		//				initializeQueryableArray();
158 		//			if (currentRequest == null)
159 		//				currentRequest = new ProfileChangeRequest(query);
160 		//		}
161 		//		debug(currentRequest);
162 		//		return currentRequest;
163 	}
164 
165 	//	private void handleSumProperty(String line, String sumProperty) {
166 	//		String value = line.substring(sumProperty.length() + 1).trim();
167 	//		try {
168 	//			currentIU.setSumProperty(Long.valueOf(value));
169 	//		} catch (NumberFormatException ex) {
170 	//			throw new IllegalArgumentException("The value \"" + value + "\" of property \"" + sumProperty + "\" cannot be summed up");
171 	//		}
172 	//	}
173 
174 	//	private void handleKeep(String line) {
175 	//		line = line.substring("keep: ".length());
176 	//		if (line.contains("version")) {
177 	//			currentKeepRequests.add(MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, currentIU.getId(), new VersionRange(currentIU.getVersion(), true, currentIU.getVersion(), true), null, false, false, true));
178 	//			return;
179 	//		}
180 	//		if (line.contains("package")) {
181 	//			currentKeepRequests.add(new RequiredCapability(currentIU.getId(), VersionRange.emptyRange, false));
182 	//			return;
183 	//		}
184 	//		if (line.contains("none"))
185 	//			return;
186 	//		if (line.contains("feature")) {
187 	//			IProvidedCapability[] caps = currentIU.getProvidedCapabilities();
188 	//			for (int i = 0; i < caps.length; i++) {
189 	//				if (!caps[i].getName().equals(currentIU.getId()))
190 	//					currentKeepRequests.add(new RequiredCapability(caps[i].getName(), caps[i].getVersion(), false));
191 	//			}
192 	//		}
193 	//
194 	//	}
195 
196 	//	private void handleExpected(String line) {
197 	//		currentRequest.setExpected(Integer.decode(line.substring("expected: ".length()).trim()).intValue());
198 	//	}
199 
handleSingleton(String line)200 	private void handleSingleton(String line) {
201 		currentIU.setSingleton(line.contains("true") ? true : false);
202 	}
203 
204 	/*
205 	 * Ensure that the current IU that we have been building is validate and if so, then
206 	 * add it to our collected list of all converted IUs from the file.
207 	 */
validateAndAddIU()208 	private void validateAndAddIU() {
209 		if (currentIU == null)
210 			return;
211 		// For a package stanza, the id and version are the only mandatory elements
212 		if (currentIU.getId() == null)
213 			throw new IllegalStateException("Malformed \'package\' stanza. No package element found.");
214 		if (currentIU.getVersion() == null)
215 			throw new IllegalStateException("Malformed \'package\' stanza. Package " + currentIU.getId() + " does not have a version.");
216 		if (currentIU.getProvidedCapabilities().size() == 0) {
217 			currentIU.setCapabilities(new IProvidedCapability[] {MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_IU_ID, currentIU.getId(), currentIU.getVersion()), MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_IU_ID, currentIU.getId(), currentIU.getVersion())});
218 		}
219 		currentIU.setUpdateDescriptor(MetadataFactory.createUpdateDescriptor(currentIU.getId(), new VersionRange(Version.emptyVersion, true, currentIU.getVersion(), false), IUpdateDescriptor.NORMAL, null));
220 		//		if (currentIU.isInstalled()) {
221 		//			keepRequests.addAll(currentKeepRequests);
222 		//		}
223 		currentIU.setProperty(InstallableUnitDescription.PROP_TYPE_GROUP, "true");
224 		allIUs.add(MetadataFactory.createInstallableUnit(currentIU));
225 		// reset to be ready for the next stanza
226 		currentIU = null;
227 	}
228 
229 	//	private void handleInstalled(String line) {
230 	//		String value = line.substring("installed: ".length());
231 	//		if (value.length() != 0) {
232 	//			if (DEBUG)
233 	//				if (!Boolean.parseBoolean(value)) {
234 	//					System.err.println("Unexpected value for installed.");
235 	//					return;
236 	//				}
237 	//			currentIU.setInstalled(true);
238 	//			preInstalled.add(new RequiredCapability(currentIU.getId(), new VersionRange(currentIU.getVersion()), true));
239 	//		}
240 	//	}
241 
242 	//	private void handleInstall(String line) {
243 	//		line = line.substring("install: ".length());
244 	//		List installRequest = createRequires(line, true, false, true);
245 	//		for (Iterator iterator = installRequest.iterator(); iterator.hasNext();) {
246 	//			currentRequest.addInstallableUnit((IRequiredCapability) iterator.next());
247 	//		}
248 	//		return;
249 	//	}
250 
251 	//	private void handleRequest(String line) {
252 	//		initializeQueryableArray();
253 	//		currentRequest = new ProfileChangeRequest(query);
254 	//		currentRequest.setPreInstalledIUs(preInstalled);
255 	//		currentRequest.setContrainstFromKeep(keepRequests);
256 	//	}
257 	//
258 	//	private void handleRemove(String line) {
259 	//		line = line.substring("remove: ".length());
260 	//		List removeRequest = createRequires(line, true, false, true);
261 	//		for (Iterator iterator = removeRequest.iterator(); iterator.hasNext();) {
262 	//			currentRequest.removeInstallableUnit((IRequiredCapability) iterator.next());
263 	//		}
264 	//		return;
265 	//	}
266 
267 	//	private void initializeQueryableArray() {
268 	//		query = new QueryableArray((InstallableUnit[]) allIUs.toArray(new InstallableUnit[allIUs.size()]));
269 	//	}
270 
271 	//	private void handleUpgrade(String line) {
272 	//		line = line.substring("upgrade: ".length());
273 	//		List updateRequest = createRequires(line, true, false, true);
274 	//		for (Iterator iterator = updateRequest.iterator(); iterator.hasNext();) {
275 	//			IRequiredCapability requirement = (IRequiredCapability) iterator.next();
276 	//			currentRequest.upgradeInstallableUnit(requirement);
277 	//
278 	//			//Add a requirement forcing uniqueness of the upgraded package in the resulting solution
279 	//			currentRequest.upgradeInstallableUnit(new RequiredCapability(requirement.getName(), VersionRange.emptyRange, 1));
280 	//
281 	//			//Add a requirement forcing the solution to be greater or equal to the highest installed version
282 	//			requirement = getHighestInstalledVersion(requirement);
283 	//			if (requirement != null)
284 	//				currentRequest.upgradeInstallableUnit(requirement);
285 	//		}
286 	//		return;
287 	//	}
288 	//
289 	//	private IRequiredCapability getHighestInstalledVersion(IRequiredCapability req) {
290 	//		Version highestVersion = null;
291 	//		Collector c = query.query(new CapabilityQuery(req), new Collector(), null);
292 	//		for (Iterator iterator = c.iterator(); iterator.hasNext();) {
293 	//			InstallableUnit candidate = (InstallableUnit) iterator.next();
294 	//			if (!candidate.isInstalled())
295 	//				continue;
296 	//			if (candidate.getId().equals(req.getName())) {
297 	//				if (highestVersion == null || candidate.getVersion().getMajor() > highestVersion.getMajor())
298 	//					highestVersion = candidate.getVersion();
299 	//			} else {
300 	//				//Requesting the upgrade of a virtual package
301 	//				IProvidedCapability[] prov = candidate.getProvidedCapabilities();
302 	//				for (int i = 0; i < prov.length; i++) {
303 	//					if (prov[i].getVersion().equals(VersionRange.emptyRange))
304 	//						continue;
305 	//					if (prov[i].getName().equals(req.getName()) && (highestVersion == null || prov[i].getVersion().getMinimum().getMajor() > highestVersion.getMajor()))
306 	//						highestVersion = prov[i].getVersion().getMinimum();
307 	//				}
308 	//			}
309 	//		}
310 	//		if (highestVersion == null)
311 	//			return null;
312 	//		return new RequiredCapability(req.getName(), new VersionRange(highestVersion, true, Version.maxVersion, true));
313 	//	}
314 
315 	/*
316 	 * Convert the version string to a version object and set it on the IU
317 	 */
handleVersion(String line)318 	private void handleVersion(String line) {
319 		currentIU.setVersion(Version.create(cudfPosintToInt(line.substring("version: ".length()))));
320 	}
321 
cudfPosintToInt(String posint)322 	private String cudfPosintToInt(String posint) {
323 		if (posint.startsWith("+")) {
324 			return posint.substring(1).trim();
325 		}
326 		return posint.trim();
327 	}
328 
handleDepends(String line)329 	private void handleDepends(String line) {
330 		mergeRequirements(createRequires(line.substring("depends: ".length()), true, false, true));
331 	}
332 
333 	//	private void handleRecommends(String line) {
334 	//		mergeRequirements(createRequires(line.substring("recommends: ".length()), true, true, true));
335 	//	}
336 
337 	/*
338 	 * Conflicts are like depends except NOT'd.
339 	 */
340 	//TODO Remove conflict for now
341 	//	private void handleConflicts(String line) {
342 	//		List reqs = createRequires(line.substring("conflicts: ".length()), false, false, false);
343 	//		List conflicts = new ArrayList();
344 	//		for (Iterator iter = reqs.iterator(); iter.hasNext();) {
345 	//			IRequiredCapability req = (IRequiredCapability) iter.next();
346 	//			if (currentIU.getId().equals(req.getName()) && req.getRange().equals(VersionRange.emptyRange)) {
347 	//				currentIU.setSingleton(true);
348 	//			} else {
349 	//				conflicts.add(new NotRequirement(req));
350 	//			}
351 	//		}
352 	//		mergeRequirements(conflicts);
353 	//	}
354 
355 	/*
356 	 * Set the given list of requirements on teh current IU. Merge if necessary.
357 	 */
mergeRequirements(List requirements)358 	private void mergeRequirements(List requirements) {
359 		if (currentIU.getRequirements() != null) {
360 			List<IRequirement> current = currentIU.getRequirements();
361 			for (IRequirement iRequirement : current) {
362 				requirements.add(iRequirement);
363 			}
364 		}
365 		currentIU.setRequirements((IRequiredCapability[]) requirements.toArray(new IRequiredCapability[requirements.size()]));
366 	}
367 
368 	/*
369 	 * Returns a map where the key is the package name and the value is a Tuple.
370 	 * If there is more than one entry for a particular package, the extra entries are included
371 	 * in the extraData field of the Tuple.
372 	 */
createPackageList(String line)373 	private List<Tuple> createPackageList(String line) {
374 		StringTokenizer tokenizer = new StringTokenizer(line, ",");
375 		List<Tuple> result = new ArrayList<>(tokenizer.countTokens());
376 		while (tokenizer.hasMoreElements()) {
377 			result.add(new Tuple(tokenizer.nextToken()));
378 		}
379 		return result;
380 	}
381 
createRequires(String line, boolean expandNotEquals, boolean optional, boolean dependency)382 	private List createRequires(String line, boolean expandNotEquals, boolean optional, boolean dependency) {
383 		ArrayList ands = new ArrayList();
384 		StringTokenizer s = new StringTokenizer(line, ",");
385 		String subtoken;
386 		while (s.hasMoreElements()) {
387 			StringTokenizer subTokenizer = new StringTokenizer(s.nextToken(), "|");
388 			if (subTokenizer.countTokens() == 1) { //This token does not contain a |.
389 				subtoken = subTokenizer.nextToken().trim();
390 				// FIXME should be handled differently in depends and conflicts.
391 				if ("true!".equals(subtoken)) {
392 					if (dependency)
393 						continue;
394 					throw new RuntimeException("Cannot have true! in a conflict!!!!!");
395 				}
396 				if ("false!".equals(subtoken)) {
397 					if (!dependency)
398 						continue;
399 					throw new RuntimeException("Cannot have false! in a dependency!!!!!");
400 				}
401 				Object o = createRequire(subtoken, expandNotEquals, optional);
402 				if (o instanceof IRequiredCapability)
403 					ands.add(o);
404 				else
405 					ands.addAll((Collection) o);
406 				continue;
407 			}
408 
409 			IRequiredCapability[] ors = new RequiredCapability[subTokenizer.countTokens()];
410 			int i = 0;
411 			while (subTokenizer.hasMoreElements()) {
412 				ors[i++] = (IRequiredCapability) createRequire(subTokenizer.nextToken().trim(), expandNotEquals, optional);
413 			}
414 			//TODO Remove OR'ing from requirements for now
415 			//			ands.add(new ORRequirement(ors, optional));
416 		}
417 		return ands;
418 	}
419 
createRequire(String nextToken, boolean expandNotEquals, boolean optional)420 	private Object createRequire(String nextToken, boolean expandNotEquals, boolean optional) {
421 		//>, >=, =, <, <=, !=
422 		StringTokenizer expressionTokens = new StringTokenizer(nextToken.trim(), ">=!<", true);
423 		int tokenCount = expressionTokens.countTokens();
424 
425 		if (tokenCount == 1) // a
426 			return MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, expressionTokens.nextToken().trim(), VersionRange.emptyRange, null, optional, false, true);
427 
428 		if (tokenCount == 3) // a > 2, a < 2, a = 2
429 			return MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, expressionTokens.nextToken().trim(), createRange3(expressionTokens.nextToken(), expressionTokens.nextToken()), null, optional, false, true);
430 
431 		if (tokenCount == 4) { //a >= 2, a <=2, a != 2
432 			String id = expressionTokens.nextToken().trim();
433 			String signFirstChar = expressionTokens.nextToken();
434 			expressionTokens.nextToken();//skip second char of the sign
435 			String version = expressionTokens.nextToken().trim();
436 			if (!("!".equals(signFirstChar))) // a >= 2 a <= 2
437 				return MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, id, createRange4(signFirstChar, version), null, optional, false, true);
438 
439 			//			//a != 2 TODO To uncomment
440 			//			if (expandNotEquals) {
441 			//				return new ORRequirement(new IRequiredCapability[] {new RequiredCapability(id, createRange3("<", version), optional), new RequiredCapability(id, createRange3(">", version), optional)}, optional);
442 			//			}
443 			ArrayList<IRequirement> res = new ArrayList<>(2);
444 			res.add(MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, id, createRange3("<", version), null, optional, false, true));
445 			res.add(MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, id, createRange3(">", version), null, optional, false, true));
446 			return res;
447 		}
448 		return null;
449 	}
450 
createRange3(String sign, String versionAsString)451 	private VersionRange createRange3(String sign, String versionAsString) {
452 		int version = Integer.decode(cudfPosintToInt(versionAsString)).intValue();
453 		sign = sign.trim();
454 		if (">".equals(sign))
455 			return new VersionRange(Version.createOSGi(version, 0, 0), false, Version.MAX_VERSION, false);
456 		if ("<".equals(sign))
457 			return new VersionRange(Version.emptyVersion, false, Version.createOSGi(version, 0, 0), false);
458 		if ("=".equals(sign))
459 			return new VersionRange(Version.createOSGi(version, 0, 0), true, Version.createOSGi(version, 0, 0), true);
460 		throw new IllegalArgumentException(sign);
461 	}
462 
createRange4(String sign, String versionAsString)463 	private VersionRange createRange4(String sign, String versionAsString) {
464 		int version = Integer.decode(cudfPosintToInt(versionAsString)).intValue();
465 		if (">".equals(sign)) //THIS IS FOR >=
466 			return new VersionRange(Version.createOSGi(version, 0, 0), true, Version.MAX_VERSION, false);
467 		if ("<".equals(sign)) //THIS IS FOR <=
468 			return new VersionRange(Version.emptyVersion, false, Version.createOSGi(version, 0, 0), true);
469 		return null;
470 	}
471 
createProvidedCapability(Tuple tuple)472 	private IProvidedCapability createProvidedCapability(Tuple tuple) {
473 		//At this point the parser only deal with standard provided capabilities and not ranges like cudf does.
474 		assert tuple.operator == null;
475 		return MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_IU_ID, tuple.name, Version.create(tuple.version));
476 		//		Set extraData = tuple.extraData;
477 		// one constraint so simply return the capability
478 		//		if (extraData == null)
479 		//			return new ProvidedCapability(tuple.name, createVersionRange(tuple.operator, tuple.version));
480 		//		// 2 constraints (e.g. a>=1, a<4) so create a real range like a[1,4)
481 		//		if (extraData.size() == 1)
482 		//			return new ProvidedCapability(tuple.name, createVersionRange(tuple, (Tuple) extraData.iterator().next()));
483 		//		// TODO merge more than 2 requirements (a>2, a<4, a>3)
484 		//		return new ProvidedCapability(tuple.name, createVersionRange(tuple.operator, tuple.version));
485 	}
486 
487 	/*
488 	 * Create and return a version range object which merges the 2 given versions and operators.
489 	 * e.g  a>=1 and a<4 becomes a[1,4)
490 	 */
491 	//	private VersionRange createVersionRange(Tuple t1, Tuple t2) {
492 	//		Version one = Version.parseVersion(t1.version);
493 	//		Version two = Version.parseVersion(t2.version);
494 	//		if (one.compareTo(two) < 0) {
495 	//			return new VersionRange(one, include(t1.operator), two, include(t2.operator));
496 	//		} else if (one.compareTo(two) == 0) {
497 	//			return new VersionRange(one, include(t1.operator), one, include(t1.operator));
498 	//		} else if (one.compareTo(two) > 0) {
499 	//			return new VersionRange(two, include(t2.operator), one, include(t1.operator));
500 	//		}
501 	//		// should never reach this. avoid compile error.
502 	//		return null;
503 	//	}
504 
505 	/*
506 	 * Helper method for when we are creating version ranges and calculating "includeMin/Max".
507 	 */
508 	//	private boolean include(String operator) {
509 	//		return "=".equals(operator) || "<=".equals(operator) || ">=".equals(operator);
510 	//	}
511 	//
512 	//	/*
513 	//	 * Create and return a version range based on the given operator and number. Note that != is
514 	//	 * handled elsewhere.
515 	//	 */
516 	//	private VersionRange createVersionRange(String operator, String number) {
517 	//		if (operator == null || number == null)
518 	//			return VersionRange.emptyRange;
519 	//		if ("=".equals(operator))
520 	//			return new VersionRange('[' + number + ',' + number + ']');
521 	//		if ("<".equals(operator))
522 	//			return new VersionRange("[0," + number + ')');
523 	//		if (">".equals(operator))
524 	//			return new VersionRange('(' + number + ',' + Integer.MAX_VALUE + ']');
525 	//		if ("<=".equals(operator))
526 	//			return new VersionRange("[0," + number + ']');
527 	//		if (">=".equals(operator))
528 	//			return new VersionRange('[' + number + ',' + Integer.MAX_VALUE + ']');
529 	//		return VersionRange.emptyRange;
530 	//	}
531 
532 	// package name matches: "^[a-zA-Z0-9+./@()%-]+$"
handlePackage(String readLine)533 	private void handlePackage(String readLine) {
534 		currentIU = new MetadataFactory.InstallableUnitDescription();
535 		currentIU.setId(readLine.substring("package: ".length()).trim());
536 	}
537 
handleProvides(String line)538 	private void handleProvides(String line) {
539 		line = line.substring("provides: ".length());
540 		List<Tuple> pkgs = createPackageList(line);
541 		IProvidedCapability[] providedCapabilities = new ProvidedCapability[pkgs.size() + 2];
542 		int i = 0;
543 		for (Tuple tuple : pkgs) {
544 			providedCapabilities[i++] = createProvidedCapability(tuple);
545 		}
546 		providedCapabilities[i++] = MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_IU_ID, currentIU.getId(), currentIU.getVersion());
547 		providedCapabilities[i++] = MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_IU_ID, currentIU.getId(), currentIU.getVersion());
548 		currentIU.setCapabilities(providedCapabilities);
549 	}
550 
551 	//	// copied from ProfileSynchronizer
552 	//	private void debug(ProfileChangeRequest request) {
553 	//		if (!DEBUG || request == null)
554 	//			return;
555 	//		//		Log.println("\nProfile Change Request:");
556 	//		//		InstallableUnit[] toAdd = request.getAddedInstallableUnit();
557 	//		//		if (toAdd == null || toAdd.length == 0) {
558 	//		//			Log.println("No installable units to add.");
559 	//		//		} else {
560 	//		//			for (int i = 0; i < toAdd.length; i++)
561 	//		//				Log.println("Adding IU: " + toAdd[i].getId() + ' ' + toAdd[i].getVersion());
562 	//		//		}
563 	//		//		Map propsToAdd = request.getInstallableUnitProfilePropertiesToAdd();
564 	//		//		if (propsToAdd == null || propsToAdd.isEmpty()) {
565 	//		//			Log.println("No IU properties to add.");
566 	//		//		} else {
567 	//		//			for (Iterator iter = propsToAdd.keySet().iterator(); iter.hasNext();) {
568 	//		//				Object key = iter.next();
569 	//		//				Log.println("Adding IU property: " + key + "->" + propsToAdd.get(key));
570 	//		//			}
571 	//		//		}
572 	//		//
573 	//		//		InstallableUnit[] toRemove = request.getRemovedInstallableUnits();
574 	//		//		if (toRemove == null || toRemove.length == 0) {
575 	//		//			Log.println("No installable units to remove.");
576 	//		//		} else {
577 	//		//			for (int i = 0; i < toRemove.length; i++)
578 	//		//				Log.println("Removing IU: " + toRemove[i].getId() + ' ' + toRemove[i].getVersion());
579 	//		//		}
580 	//		//		Map propsToRemove = request.getInstallableUnitProfilePropertiesToRemove();
581 	//		//		if (propsToRemove == null || propsToRemove.isEmpty()) {
582 	//		//			Log.println("No IU properties to remove.");
583 	//		//		} else {
584 	//		//			for (Iterator iter = propsToRemove.keySet().iterator(); iter.hasNext();) {
585 	//		//				Object key = iter.next();
586 	//		//				Log.println("Removing IU property: " + key + "->" + propsToRemove.get(key));
587 	//		//			}
588 	//		//		}
589 	//	}
590 
591 	// dump info to console
debug(InstallableUnit unit)592 	private void debug(InstallableUnit unit) {
593 		//		if (!DEBUG)
594 		//			return;
595 		//		Log.println("\nInstallableUnit: " + unit.getId());
596 		//		Log.println("Version: " + unit.getVersion());
597 		//		if (unit.isInstalled())
598 		//			Log.println("Installed: true");
599 		//		IRequiredCapability[] reqs = unit.getRequiredCapabilities();
600 		//		for (int i = 0; i < reqs.length; i++) {
601 		//			Log.println("Requirement: " + reqs[i]);
602 		//		}
603 	}
604 
getIU()605 	public IInstallableUnit getIU() {
606 		assert allIUs.size() == 1;
607 		return allIUs.get(0);
608 	}
609 }
610