Skip to content

Commit

Permalink
Add support for using wildcards in the IUBundleContainer
Browse files Browse the repository at this point in the history
Currently one has to specify an exact id for an IU to be used in a
target but sometimes it is a bit cumbersome to do so. Also it can become
quite annoying if items are added/removed to update the target.

This adds a new way of specify the id with wildcards that is enabled
whenever the id contains an '*' (any number characters) or '?' (a single
character), the container constructs a pattern and includes everything
that matches this pattern to be considered.
  • Loading branch information
laeubi committed Jan 20, 2024
1 parent 76e5d1f commit a13f7b8
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2009, 2021 IBM Corporation and others.
* Copyright (c) 2009, 2023 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -15,6 +15,7 @@
* Manumitting Technologies Inc - bug 437726: wrong error messages opening target definition
* Alexander Fedorov (ArSysOp) - Bug 542425, Bug 574629
* Christoph Läubrich - Bug 568865 - [target] add advanced editing capabilities for custom target platforms
* - support wildcard in IU
*******************************************************************************/
package org.eclipse.pde.internal.core.target;

Expand All @@ -33,7 +34,10 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
Expand Down Expand Up @@ -76,6 +80,10 @@
*/
public class IUBundleContainer extends AbstractBundleContainer {

private static final String QUESTION_MARK = "?"; //$NON-NLS-1$

private static final String ASTERIX = "*"; //$NON-NLS-1$

/**
* Constant describing the type of bundle container
*/
Expand Down Expand Up @@ -262,14 +270,22 @@ protected TargetBundle[] resolveBundles(ITargetDefinition definition, IProgressM
IInstallableUnit[] cacheIUs(ITargetDefinition target) throws CoreException {
IProfile profile = fSynchronizer.getProfile();
ArrayList<IInstallableUnit> result = new ArrayList<>();
MultiStatus status = new MultiStatus(PDECore.PLUGIN_ID, 0, Messages.IUBundleContainer_ProblemsLoadingRepositories, null);
MultiStatus status = new MultiStatus(PDECore.PLUGIN_ID, 0,
Messages.IUBundleContainer_ProblemsLoadingRepositories, null);
for (int i = 0; i < fIds.length; i++) {
IQuery<IInstallableUnit> query = QueryUtil.createIUQuery(fIds[i], fVersions[i]);
IQueryResult<IInstallableUnit> queryResult = profile.query(query, null);
if (queryResult.isEmpty()) {
status.add(Status.error(NLS.bind(Messages.IUBundleContainer_1, fIds[i] + " " + fVersions[i]))); //$NON-NLS-1$
String id = fIds[i];
Version version = fVersions[i];
Pattern pattern = createIdPattern(id, status);
if (pattern == null) {
IQuery<IInstallableUnit> query = QueryUtil.createIUQuery(id, version);
IQueryResult<IInstallableUnit> queryResult = profile.query(query, null);
if (queryResult.isEmpty()) {
status.add(Status.error(NLS.bind(Messages.IUBundleContainer_1, id + " " + version))); //$NON-NLS-1$
} else {
result.add(queryResult.iterator().next());
}
} else {
result.add(queryResult.iterator().next());
queryWithPattern(profile, result, version, pattern);
}
}
if (!status.isOK()) {
Expand Down Expand Up @@ -744,12 +760,20 @@ IInstallableUnit[] getRootIUs(ITargetDefinition definition, IProgressMonitor mon
List<IInstallableUnit> result = new ArrayList<>();
for (int j = 0; j < fIds.length; j++) {
// For versions such as 0.0.0, the IU query may return multiple IUs, so we check which is the latest version
IQuery<IInstallableUnit> query = QueryUtil.createLatestQuery(QueryUtil.createIUQuery(fIds[j], fVersions[j]));
IQueryResult<IInstallableUnit> queryResult = repos.query(query, null);
if (queryResult.isEmpty()) {
status.add(Status.error(NLS.bind(Messages.IUBundleContainer_1, fIds[j] + " " + fVersions[j])));//$NON-NLS-1$
String id = fIds[j];
Version version = fVersions[j];
Pattern pattern = createIdPattern(id, status);
IQueryResult<IInstallableUnit> queryResult;
if (pattern == null) {
IQuery<IInstallableUnit> query = QueryUtil.createLatestQuery(QueryUtil.createIUQuery(id, version));
queryResult = repos.query(query, null);
if (queryResult.isEmpty()) {
status.add(Status.error(NLS.bind(Messages.IUBundleContainer_1, id + " " + version)));//$NON-NLS-1$
} else {
result.add(queryResult.iterator().next());
}
} else {
result.add(queryResult.iterator().next());
queryWithPattern(repos, result, version, pattern);
}
}
if (!status.isOK()) {
Expand All @@ -759,6 +783,37 @@ IInstallableUnit[] getRootIUs(ITargetDefinition definition, IProgressMonitor mon
return result.toArray(new IInstallableUnit[0]);
}

private static void queryWithPattern(IQueryable<IInstallableUnit> repos, List<IInstallableUnit> result,
Version version,
Pattern pattern) {
Stream<IInstallableUnit> allMatchingPattern = repos.query(QueryUtil.ALL_UNITS, null).stream()
.filter(iu -> pattern.matcher(iu.getId()).matches());
if (version == null || Version.emptyVersion.equals(version)) {
allMatchingPattern
.collect(Collectors.groupingBy(IInstallableUnit::getId)).values().stream().flatMap(
list -> list.stream().sorted(Comparator.comparing(IInstallableUnit::getVersion).reversed()))
.forEach(result::add);
} else {
allMatchingPattern.filter(iu -> version.compareTo(iu.getVersion()) == 0).forEach(result::add);
}
}

private static Pattern createIdPattern(String id, MultiStatus status) {
if (id.contains(ASTERIX) || id.contains(QUESTION_MARK)) {
try {
String pattern = id;
pattern = pattern.replace(".", "\\."); //$NON-NLS-1$//$NON-NLS-2$
pattern = pattern.replace("-", "\\-"); //$NON-NLS-1$ //$NON-NLS-2$
pattern = pattern.replace('?', '.');
pattern = pattern.replace("*", ".*"); //$NON-NLS-1$ //$NON-NLS-2$
return Pattern.compile(String.format("^%s$", pattern), Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
} catch (IllegalArgumentException iae) {
status.add(Status.error(Messages.IUBundleContainer_12, iae));
}
}
return null;
}

@Override
public <T> T getAdapter(Class<T> adapter) {
if (adapter.isInstance(fSynchronizer)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class Messages extends NLS {
public static String IUBundleContainer_1;
public static String IUBundleContainer_10;
public static String IUBundleContainer_11;
public static String IUBundleContainer_12;
public static String IUBundleContainer_2;
public static String IUBundleContainer_3;
public static String IUBundleContainer_4;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ IUBundleContainer_0=Provisioning target
IUBundleContainer_1=Unable to locate installable unit {0}
IUBundleContainer_10=Provisioning Agent Location service not found
IUBundleContainer_11=Global Provisioning Agent service not found
IUBundleContainer_12=Can not compile pattern: {0} because of {1}
IUBundleContainer_2=Metadata repository service not found
IUBundleContainer_3=Artifact respository service not found
IUBundleContainer_3=Artifact repository service not found
IUBundleContainer_4=Provisioning engine not found
IUBundleContainer_5=Provisioning planner not found
IUBundleContainer_6=Target provisioning skipped install plan
Expand Down

0 comments on commit a13f7b8

Please sign in to comment.