Skip to content

Commit

Permalink
Simplify Installable-Unit handling in IUBundleContainer
Browse files Browse the repository at this point in the history
  • Loading branch information
HannesWell committed Apr 21, 2024
1 parent c3d37b0 commit c245bb9
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
import java.io.StringWriter;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
Expand All @@ -34,8 +34,6 @@
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
Expand Down Expand Up @@ -115,21 +113,14 @@ public class IUBundleContainer extends AbstractBundleContainer {
*/
public static final int INCLUDE_CONFIGURE_PHASE = 1 << 3;

/**
* IU identifiers.
*/
private String[] fIds;

/**
* IU versions
*/
private Version[] fVersions;
/** The list of id+version of all root units declared in this container. */
private List<IVersionedId> fIUs;

/**
* Cached IU's referenced by this bundle container, or <code>null</code> if not
* resolved.
*/
private IInstallableUnit[] fUnits;
private List<IInstallableUnit> fUnits = List.of();

/**
* Repositories to consider, or <code>null</code> if default.
Expand All @@ -156,16 +147,14 @@ public class IUBundleContainer extends AbstractBundleContainer {
/**
* Constructs a installable unit bundle container for the specified units.
*
* @param ids IU identifiers
* @param versions IU versions
* @param units the units composed of their identifier and version
* @param repositories metadata repositories used to search for IU's or <code>null</code> for default set
* @param resolutionFlags bitmask of flags to control IU resolution, possible flags are {@link IUBundleContainer#INCLUDE_ALL_ENVIRONMENTS}, {@link IUBundleContainer#INCLUDE_REQUIRED}, {@link IUBundleContainer#INCLUDE_SOURCE}, {@link IUBundleContainer#INCLUDE_CONFIGURE_PHASE}
*/
IUBundleContainer(String[] ids, Version[] versions, URI[] repositories, int resolutionFlags) {
fIds = ids;
IUBundleContainer(Collection<IVersionedId> units, List<URI> repositories, int resolutionFlags) {
fIUs = new ArrayList<>(units);
fFlags = resolutionFlags;
fVersions = versions;
fRepos = repositories == null || repositories.length == 0 ? List.of() : List.of(repositories);
fRepos = List.copyOf(repositories);
}

@Override
Expand Down Expand Up @@ -262,22 +251,22 @@ private void cacheIUs() throws CoreException {
IProfile profile = fSynchronizer.getProfile();
List<IInstallableUnit> result = new ArrayList<>();
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]);
addElement(profile, query, i, result, status);
for (IVersionedId unit : fIUs) {
IQuery<IInstallableUnit> query = QueryUtil.createIUQuery(unit);
addElement(profile, query, unit, result, status);
}
if (!status.isOK()) {
fResolutionStatus = status;
throw new CoreException(status);
}
fUnits = result.toArray(new IInstallableUnit[result.size()]);
fUnits = List.copyOf(result);
}

private void addElement(IQueryable<IInstallableUnit> queryable, IQuery<IInstallableUnit> query, int index,
private void addElement(IQueryable<IInstallableUnit> queryable, IQuery<IInstallableUnit> query, IVersionedId iu,
List<IInstallableUnit> result, MultiStatus status) {
Optional<IInstallableUnit> queryResult = queryFirst(queryable, query, null);
if (queryResult.isEmpty()) {
status.add(Status.error(NLS.bind(Messages.IUBundleContainer_1, fIds[index] + " " + fVersions[index]))); //$NON-NLS-1$
status.add(Status.error(NLS.bind(Messages.IUBundleContainer_1, iu)));
} else {
result.add(queryResult.get());
}
Expand All @@ -302,7 +291,7 @@ private void cacheBundles(ITargetDefinition target) throws CoreException {
boolean onlyStrict = !fSynchronizer.getIncludeAllRequired();
IProfile metadata = fSynchronizer.getProfile();
PermissiveSlicer slicer = new PermissiveSlicer(metadata, new HashMap<>(), true, false, true, onlyStrict, false);
IQueryable<IInstallableUnit> slice = slicer.slice(Arrays.asList(fUnits), new NullProgressMonitor());
IQueryable<IInstallableUnit> slice = slicer.slice(fUnits, new NullProgressMonitor());

if (slicer.getStatus().getSeverity() == IStatus.ERROR) {
// If the slicer has an error, report it instead of returning an empty set
Expand Down Expand Up @@ -378,30 +367,29 @@ public synchronized IUBundleContainer update(Set<String> toUpdate, IProgressMoni
SubMonitor progress = SubMonitor.convert(monitor, 100);
IQueryable<IInstallableUnit> source = P2TargetUtils.getQueryableMetadata(fRepos, progress.split(30));
boolean updated = false;
String[] updateIDs = fIds.clone();
Version[] updateVersions = fVersions.clone();
SubMonitor loopProgress = progress.split(70).setWorkRemaining(updateIDs.length);
for (int i = 0; i < updateIDs.length; i++) {
String id = updateIDs[i];
if (!toUpdate.isEmpty() && !toUpdate.contains(id)) {
List<IVersionedId> updatedUnits = new ArrayList<>(fIUs);
SubMonitor loopProgress = progress.split(70).setWorkRemaining(updatedUnits.size());
for (int i = 0; i < updatedUnits.size(); i++) {
IVersionedId unit = updatedUnits.get(i);
if (!toUpdate.isEmpty() && !toUpdate.contains(unit.getId())) {
continue;
}
IQuery<IInstallableUnit> query = QueryUtil.createLatestQuery(QueryUtil.createIUQuery(id));
IQuery<IInstallableUnit> query = QueryUtil.createLatestQuery(QueryUtil.createIUQuery(unit.getId()));
Optional<IInstallableUnit> queryResult = queryFirst(source, query, loopProgress.split(1));
Version updatedVersion = queryResult.map(IInstallableUnit::getVersion)
// bail if the feature is no longer available.
.orElseThrow(() -> new CoreException(Status.error(NLS.bind(Messages.IUBundleContainer_1, id))));
.orElseThrow(() -> new CoreException(Status.error(NLS.bind(Messages.IUBundleContainer_1, unit))));
// if the version is different from the spec (up or down), record the change.
if (!updatedVersion.equals(updateVersions[i])) {
if (!updatedVersion.equals(unit.getVersion())) {
updated = true;
// if the spec was not specific (e.g., 0.0.0) the target def itself has changed.
if (!updateVersions[i].equals(Version.emptyVersion)) {
updateVersions[i] = updatedVersion;
if (!unit.getVersion().equals(Version.emptyVersion)) {
updatedUnits.set(i, new VersionedId(unit.getId(), updatedVersion));
}
}
}
if (updated) {
return new IUBundleContainer(updateIDs, updateVersions, fRepos.toArray(URI[]::new), fFlags);
return new IUBundleContainer(updatedUnits, fRepos, fFlags);
}
return null;
}
Expand Down Expand Up @@ -467,7 +455,7 @@ private void generateBundle(IInstallableUnit unit, IFileArtifactRepository repo,
@Override
public int hashCode() {
return Objects.hash(getIncludeAllRequired(), getIncludeAllEnvironments(), getIncludeSource(),
getIncludeConfigurePhase(), Arrays.asList(fIds), fRepos, Arrays.asList(fVersions));
getIncludeConfigurePhase(), fIUs, fRepos);
}

@Override
Expand All @@ -480,8 +468,7 @@ && getIncludeAllRequired() == other.getIncludeAllRequired()
&& getIncludeAllEnvironments() == other.getIncludeAllEnvironments()
&& getIncludeSource() == other.getIncludeSource()
&& getIncludeConfigurePhase() == other.getIncludeConfigurePhase() //
&& Arrays.equals(fIds, other.fIds) //
&& Arrays.equals(fVersions, other.fVersions) //
&& fIUs.equals(other.fIUs) //
&& fRepos.equals(other.fRepos);
}

Expand All @@ -501,17 +488,7 @@ public List<URI> getRepositories() {
* @param unit unit to remove from the list of root IUs
*/
public synchronized void removeInstallableUnit(IInstallableUnit unit) {
List<String> newIds = new ArrayList<>(fIds.length);
List<Version> newVersions = new ArrayList<>(fIds.length);
for (int i = 0; i < fIds.length; i++) {
if (!fIds[i].equals(unit.getId()) || !fVersions[i].equals(unit.getVersion())) {
newIds.add(fIds[i]);
newVersions.add(fVersions[i]);
}
}
fIds = newIds.toArray(new String[newIds.size()]);
fVersions = newVersions.toArray(new Version[newVersions.size()]);

fIUs.remove(new VersionedId(unit.getId(), unit.getVersion()));
// Need to mark the container as unresolved
clearResolutionStatus();
}
Expand Down Expand Up @@ -584,28 +561,12 @@ public boolean getIncludeConfigurePhase() {
* @exception CoreException if unable to retrieve IU's
*/
public List<IInstallableUnit> getInstallableUnits() throws CoreException {
if (fUnits == null) {
return List.of();
}
return Arrays.asList(fUnits);
return fUnits;
}

/**
* Returns installable unit identifiers.
*
* @return IU id's
*/
String[] getIds() {
return fIds;
}

/**
* Returns installable unit versions.
*
* @return IU versions
*/
Version[] getVersions() {
return fVersions;
/** Returns installable unit identifiers and versions. */
List<IVersionedId> getUnits() {
return Collections.unmodifiableList(fIUs);
}

/**
Expand Down Expand Up @@ -667,18 +628,13 @@ public String serialize() {
containerElement.setAttribute(TargetDefinitionPersistenceHelper.ATTR_INCLUDE_ALL_PLATFORMS, Boolean.toString(getIncludeAllEnvironments()));
containerElement.setAttribute(TargetDefinitionPersistenceHelper.ATTR_INCLUDE_SOURCE, Boolean.toString(getIncludeSource()));
containerElement.setAttribute(TargetDefinitionPersistenceHelper.ATTR_INCLUDE_CONFIGURE_PHASE, Boolean.toString(getIncludeConfigurePhase()));
List<URI> repositories = new ArrayList<>(getRepositories());
repositories.sort(null);
for (URI repository : repositories) {
for (URI repository : fRepos) {
Element repo = document.createElement(TargetDefinitionPersistenceHelper.REPOSITORY);
repo.setAttribute(TargetDefinitionPersistenceHelper.LOCATION, repository.toASCIIString());
containerElement.appendChild(repo);
}
// Generate a predictable order of the elements
String[] ids = getIds();
Version[] versions = getVersions();
Stream<VersionedId> ius = IntStream.range(0, fIds.length).mapToObj(i -> new VersionedId(ids[0], versions[i]));
ius.sorted(ID_FIRST_VERSION_SECOND).forEach(iu -> {
fIUs.stream().sorted(ID_FIRST_VERSION_SECOND).forEach(iu -> {
Element unit = document.createElement(TargetDefinitionPersistenceHelper.INSTALLABLE_UNIT);
unit.setAttribute(TargetDefinitionPersistenceHelper.ATTR_ID, iu.getId());
unit.setAttribute(TargetDefinitionPersistenceHelper.ATTR_VERSION, iu.getVersion().toString());
Expand All @@ -703,10 +659,10 @@ IInstallableUnit[] getRootIUs(IProgressMonitor monitor) throws CoreException {
IQueryable<IInstallableUnit> repos = P2TargetUtils.getQueryableMetadata(getRepositories(), monitor);
MultiStatus status = new MultiStatus(PDECore.PLUGIN_ID, 0, Messages.IUBundleContainer_ProblemsLoadingRepositories, null);
List<IInstallableUnit> result = new ArrayList<>();
for (int j = 0; j < fIds.length; j++) {
for (IVersionedId iu : fIUs) {
// 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]));
addElement(repos, query, j, result, status);
IQuery<IInstallableUnit> query = QueryUtil.createLatestQuery(QueryUtil.createIUQuery(iu));
addElement(repos, query, iu, result, status);
}
if (!status.isOK()) {
fResolutionStatus = status;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.IProvidedCapability;
import org.eclipse.equinox.p2.metadata.IRequirement;
import org.eclipse.equinox.p2.metadata.IVersionedId;
import org.eclipse.equinox.p2.metadata.MetadataFactory;
import org.eclipse.equinox.p2.metadata.MetadataFactory.InstallableUnitDescription;
import org.eclipse.equinox.p2.metadata.Version;
Expand Down Expand Up @@ -527,11 +528,9 @@ private boolean checkProfile(ITargetDefinition target, final IProfile profile) {
}
for (ITargetLocation container : containers) {
if (container instanceof IUBundleContainer bc) {
String[] ids = bc.getIds();
Version[] versions = bc.getVersions();
for (int j = 0; j < versions.length; j++) {
for (IVersionedId iu : bc.getUnits()) {
// if there is something in a container but not in the profile, recreate
if (!installedIUs.remove(new NameVersionDescriptor(ids[j], versions[j].toString()))) {
if (!installedIUs.remove(new NameVersionDescriptor(iu.getId(), iu.getVersion().toString()))) {
return false;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
Expand All @@ -35,6 +36,7 @@
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import org.eclipse.core.resources.IFile;
Expand All @@ -59,7 +61,8 @@
import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.equinox.frameworkadmin.BundleInfo;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.Version;
import org.eclipse.equinox.p2.metadata.IVersionedId;
import org.eclipse.equinox.p2.metadata.VersionedId;
import org.eclipse.osgi.service.datalocation.Location;
import org.eclipse.osgi.util.NLS;
import org.eclipse.pde.core.plugin.IPluginModelBase;
Expand Down Expand Up @@ -641,22 +644,18 @@ public IStatus compareWithTargetPlatform(ITargetDefinition target) throws CoreEx

@Override
public ITargetLocation newIULocation(IInstallableUnit[] units, URI[] repositories, int resolutionFlags) {
String[] fIds = new String[units.length];
Version[] fVersions = new Version[units.length];
for (int i = 0; i < units.length; i++) {
fIds[i] = units[i].getId();
fVersions[i] = units[i].getVersion();
}
return new IUBundleContainer(fIds, fVersions, repositories, resolutionFlags);
Stream<IVersionedId> ius = Arrays.stream(units).map(iu -> new VersionedId(iu.getId(), iu.getVersion()));
return new IUBundleContainer(ius.toList(), List.of(repositories), resolutionFlags);
}

@Override
public ITargetLocation newIULocation(String[] unitIds, String[] versions, URI[] repositories, int resolutionFlags) {
Version[] fVersions = new Version[versions.length];
for (int i = 0; i < versions.length; i++) {
fVersions[i] = Version.create(versions[i]);
if (unitIds.length != versions.length) {
throw new IllegalArgumentException("Units and versions must have the same length"); //$NON-NLS-1$
}
return new IUBundleContainer(unitIds, fVersions, repositories, resolutionFlags);
Stream<IVersionedId> ius = IntStream.range(0, unitIds.length)
.mapToObj(i -> new VersionedId(unitIds[i], versions[i]));
return new IUBundleContainer(ius.toList(), List.of(repositories), resolutionFlags);
}

}

0 comments on commit c245bb9

Please sign in to comment.