Skip to content

Commit

Permalink
[TP-Editor] Consider all repositories of location for proposals
Browse files Browse the repository at this point in the history
  • Loading branch information
HannesWell committed Oct 19, 2024
1 parent d1d2812 commit d141f1d
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
package org.eclipse.pde.internal.genericeditor.target.extension.autocomplete.processors;

import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import org.eclipse.equinox.p2.metadata.IVersionedId;
import org.eclipse.jface.text.contentassist.CompletionProposal;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.pde.internal.genericeditor.target.extension.autocomplete.InstallableUnitProposal;
Expand All @@ -28,7 +30,6 @@
import org.eclipse.pde.internal.genericeditor.target.extension.model.RepositoryCache;
import org.eclipse.pde.internal.genericeditor.target.extension.model.UnitNode;
import org.eclipse.pde.internal.genericeditor.target.extension.model.xml.Parser;
import org.osgi.framework.Version;

/**
* Class that computes autocompletions for attribute values. Example:
Expand Down Expand Up @@ -81,12 +82,12 @@ public ICompletionProposal[] getCompletionProposals() {
if (!(node.getParentNode() instanceof LocationNode location)) {
return getErrorCompletion();
}
String repoLocation = location.getRepositoryLocation();
if (repoLocation == null) {
List<String> repoLocations = location.getRepositoryLocations();
if (repoLocations.isEmpty()) {
return getErrorCompletion();
}
List<UnitNode> units = RepositoryCache.fetchP2UnitsFromRepo(repoLocation);
return toProposals(units.stream().map(UnitNode::getId).sorted(String.CASE_INSENSITIVE_ORDER));
Map<String, List<IVersionedId>> units = RepositoryCache.fetchP2UnitsFromRepos(repoLocations);
return toProposals(units.keySet().stream());
}
}

Expand All @@ -95,20 +96,15 @@ public ICompletionProposal[] getCompletionProposals() {
if (!(node.getParentNode() instanceof LocationNode location)) {
return getErrorCompletion();
}
String repoLocation = location.getRepositoryLocation();
if (repoLocation == null) {
List<String> repoLocations = location.getRepositoryLocations();
if (repoLocations.isEmpty()) {
return getErrorCompletion();
}
List<UnitNode> repositoryUnits = RepositoryCache.fetchP2UnitsFromRepo(repoLocation);
List<String> versions = null;
for (UnitNode unit : repositoryUnits) {
if (unit.getId().equals(node.getId())) {
versions = unit.getAvailableVersions();
}
}
Map<String, List<IVersionedId>> units = RepositoryCache.fetchP2UnitsFromRepos(repoLocations);
List<IVersionedId> versions = units.get(node.getId());
if (versions != null) {
Stream<String> availableVersions = Stream.concat(
versions.stream().sorted((v1, v2) -> new Version(v2).compareTo(new Version(v1))),
versions.stream().map(unit -> unit.getVersion().toString()),
Stream.of(ITargetConstants.UNIT_VERSION_ATTR_GENERIC));
return toProposals(availableVersions.distinct());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
*******************************************************************************/
package org.eclipse.pde.internal.genericeditor.target.extension.command;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

import javax.xml.stream.XMLStreamException;
Expand All @@ -23,6 +23,7 @@
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.equinox.p2.metadata.IVersionedId;
import org.eclipse.jface.dialogs.IPageChangeProvider;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.IDocument;
Expand All @@ -39,7 +40,6 @@
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
import org.osgi.framework.Version;

public class UpdateUnitVersions extends AbstractHandler {

Expand Down Expand Up @@ -71,19 +71,20 @@ public Object execute(ExecutionEvent event) throws ExecutionException {
String documentText = document.get();
for (Node n1 : locationsNode.get(0).getChildNodesByTag(ITargetConstants.LOCATION_TAG)) {
LocationNode locationNode = (LocationNode) n1;
String repositoryLocation = locationNode.getRepositoryLocation();
if (repositoryLocation == null) {
List<String> repositoryLocations = locationNode.getRepositoryLocations();
if (repositoryLocations.isEmpty()) {
continue;
}
if (!RepositoryCache.isUpToDate(repositoryLocation)) {
if (!repositoryLocations.stream().allMatch(RepositoryCache::isUpToDate)) {
try {
updateCache(locationNode);
} catch (InterruptedException e) {
e.printStackTrace();
continue;
}
}
List<UnitNode> repositoryUnits = RepositoryCache.fetchP2UnitsFromRepo(repositoryLocation);
Map<String, List<IVersionedId>> repositoryUnits = RepositoryCache
.fetchP2UnitsFromRepos(repositoryLocations);
for (Node n2 : locationNode.getChildNodesByTag(ITargetConstants.UNIT_TAG)) {
UnitNode unitNode = ((UnitNode) n2);
String declaredVersion = unitNode.getVersion();
Expand All @@ -95,19 +96,12 @@ public Object execute(ExecutionEvent event) throws ExecutionException {
if (declaredVersion == null || !isValidExplicitVersion) {
continue;
}
List<String> versions = null;
for (UnitNode unit : repositoryUnits) {
if (unit.getId().equals(unitNode.getId())) {
versions = unit.getAvailableVersions();
break;
}
}
List<IVersionedId> versions = repositoryUnits.get(unitNode.getId());
if (versions == null || versions.isEmpty()) {
continue;
}
Collections.sort(versions, (v1, v2) -> (new Version(v2)).compareTo(new Version(v1)));
String version = versions.get(0);
if (version == null || version.isEmpty() || version.equals(declaredVersion)) {
String version = versions.get(0).getVersion().toString();
if (version.isEmpty() || version.equals(declaredVersion)) {
continue;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2016, 2017 Red Hat Inc. and others
* Copyright (c) 2016, 2024 Red Hat Inc. and others
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -14,19 +14,22 @@
*******************************************************************************/
package org.eclipse.pde.internal.genericeditor.target.extension.model;

import java.util.ArrayList;
import java.util.List;

/**
* Models the &lt;location&gt; nodes
*/
public class LocationNode extends Node {

private String repositoryLocation;
private List<String> repositoryLocations = new ArrayList<>();

public String getRepositoryLocation() {
return repositoryLocation;
public List<String> getRepositoryLocations() {
return repositoryLocations;
}

public void setRepositoryLocation(String repositoryLocation) {
this.repositoryLocation = repositoryLocation;
public void addRepositoryLocation(String repositoryLocation) {
this.repositoryLocations.add(repositoryLocation);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,17 @@
*******************************************************************************/
package org.eclipse.pde.internal.genericeditor.target.extension.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.eclipse.equinox.p2.metadata.IVersionedId;
import org.eclipse.pde.internal.genericeditor.target.extension.p2.P2Fetcher;

/**
Expand All @@ -34,16 +41,42 @@ private RepositoryCache() {
//avoid instantiation
}

private static final Map<String, List<UnitNode>> CACHE = new ConcurrentHashMap<>();
private static final Map<String, Map<String, List<IVersionedId>>> CACHE = new ConcurrentHashMap<>();

/**
* Fetches information and caches it.
*
* @return list of IUs available in the 'repo' repository. Never
* <code>null</code>.
* <p>
* All available IUs are returned as a map mapping the IDs of all IUs
* available in the {@code repositories} to the list of all available
* {@link IVersionedId versioned IDs} for that ID. All keys are sorted in
* alphabetical order and all versions are sorted in descending order.
* </p>
*
* @return all available units in the specified {@code repository} in a map
* mapping all IDs to all available versions.
*/
public static List<UnitNode> fetchP2UnitsFromRepo(String repo) {
return CACHE.computeIfAbsent(repo, P2Fetcher::fetchAvailableUnits);
public static Map<String, List<IVersionedId>> fetchP2UnitsFromRepos(List<String> repositories) {
if (repositories.size() == 1) {
return fetchP2UnitsFromRepo(repositories.get(0));
}
List<Map<String, List<IVersionedId>>> units = new ArrayList<>(repositories.size());
for (String repository : repositories) {
units.add(fetchP2UnitsFromRepo(repository));
}
return toSortedMap(units.stream().map(Map::values).flatMap(Collection::stream).flatMap(List::stream));
}

private static Map<String, List<IVersionedId>> fetchP2UnitsFromRepo(String repository) {
return CACHE.computeIfAbsent(repository, r -> toSortedMap(P2Fetcher.fetchAvailableUnits(r)));
}

private static final Comparator<IVersionedId> BY_ID_FIRST_THEN_DESCENDING_VERSION = Comparator
.comparing(IVersionedId::getId, String.CASE_INSENSITIVE_ORDER)
.thenComparing(IVersionedId::getVersion, Comparator.reverseOrder());

private static Map<String, List<IVersionedId>> toSortedMap(Stream<IVersionedId> units) {
return units.sorted(BY_ID_FIRST_THEN_DESCENDING_VERSION).collect(
Collectors.groupingBy(IVersionedId::getId, LinkedHashMap::new, Collectors.toUnmodifiableList()));
}

/**
Expand All @@ -63,9 +96,10 @@ public static List<UnitNode> fetchP2UnitsFromRepo(String repo) {
* A prefix used to narrow down the match list
* @return A list of IUs whose id starts with 'prefix'
*/
public static List<UnitNode> getUnitsByPrefix(String repo, String prefix) {
List<UnitNode> allUnits = fetchP2UnitsFromRepo(repo);
return allUnits.stream().filter(unit -> unit.getId().startsWith(prefix)).toList();
public static List<IVersionedId> getUnitsByPrefix(String repo, String prefix) {
Map<String, List<IVersionedId>> allUnits = fetchP2UnitsFromRepos(List.of(repo));
return allUnits.values().stream().flatMap(List::stream) //
.filter(unit -> unit.getId().startsWith(prefix)).toList();
}

/**
Expand All @@ -86,9 +120,10 @@ public static List<UnitNode> getUnitsByPrefix(String repo, String prefix) {
* A prefix used to narrow down the match list
* @return A list of IUs whose id contains 'searchTerm'
*/
public static List<UnitNode> getUnitsBySearchTerm(String repo, String searchTerm) {
List<UnitNode> allUnits = fetchP2UnitsFromRepo(repo);
return allUnits.stream().filter(unit -> unit.getId().contains(searchTerm)).toList();
public static List<IVersionedId> getUnitsBySearchTerm(String repo, String searchTerm) {
Map<String, List<IVersionedId>> allUnits = fetchP2UnitsFromRepos(List.of(repo));
return allUnits.values().stream().flatMap(List::stream) //
.filter(unit -> unit.getId().contains(searchTerm)).toList();
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2016, 2022 Red Hat Inc. and others
* Copyright (c) 2016, 2024 Red Hat Inc. and others
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -76,9 +76,9 @@ public void parse(IDocument document) throws XMLStreamException {
currentNode = new DependencyNode();
} else if (ITargetConstants.REPOSITORY_TAG.equalsIgnoreCase(name)) {
currentNode = new Node();
if (currentParent instanceof LocationNode) {
if (currentParent instanceof LocationNode containerLocation) {
String locationValue = event.getAttributeValueByKey(ITargetConstants.REPOSITORY_LOCATION_ATTR);
((LocationNode) currentParent).setRepositoryLocation(locationValue);
containerLocation.addRepositoryLocation(locationValue);
}
} else if (ITargetConstants.TARGET_TAG.equalsIgnoreCase(name)) {
target = new Node();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2016, 2018 Red Hat Inc. and others
* Copyright (c) 2016, 2024 Red Hat Inc. and others
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -15,15 +15,15 @@

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;

import org.eclipse.core.runtime.ILog;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.core.IProvisioningAgentProvider;
import org.eclipse.equinox.p2.core.ProvisionException;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.IVersionedId;
import org.eclipse.equinox.p2.metadata.VersionedId;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository;
Expand All @@ -46,51 +46,32 @@ public class P2Fetcher {
* URL string of a p2 repository
* @return List of available installable unit models. See {@link UnitNode}
*/
public static List<UnitNode> fetchAvailableUnits(String repositoryLocation) {
List<UnitNode> units = new ArrayList<>();
IQueryResult<IInstallableUnit> result = null;
public static Stream<IVersionedId> fetchAvailableUnits(String repositoryLocation) {
try {
URI uri;
try {
uri = new URI(repositoryLocation);
} catch (URISyntaxException e) {
return units;
}
URI uri = new URI(repositoryLocation);

BundleContext context = FrameworkUtil.getBundle(P2Fetcher.class).getBundleContext();
ServiceReference<IProvisioningAgentProvider> sr = context
.getServiceReference(IProvisioningAgentProvider.class);
IProvisioningAgentProvider agentProvider = null;
agentProvider = context.getService(sr);
IProvisioningAgentProvider agentProvider = context.getService(sr);
IProvisioningAgent agent = null;

try {
agent = agentProvider.createAgent(null);
} catch (ProvisionException e) {
e.printStackTrace();
ILog.get().error("Failed to create provisioning-agent", e);
} finally {
context.ungetService(sr);
}
IMetadataRepositoryManager manager = (IMetadataRepositoryManager) agent
.getService(IMetadataRepositoryManager.SERVICE_NAME);
IMetadataRepositoryManager manager = agent.getService(IMetadataRepositoryManager.class);
IMetadataRepository repository = manager.loadRepository(uri, null);
result = repository.query(QueryUtil.createLatestIUQuery(), null);

Iterator<IInstallableUnit> iterator = result.iterator();
while (iterator.hasNext()) {
IInstallableUnit unit = iterator.next();
UnitNode modelUnit = new UnitNode();
modelUnit.setId(unit.getId());
modelUnit.setVersion(unit.getVersion().getOriginal());
IQueryResult<IInstallableUnit> versions = repository.query(QueryUtil.createIUQuery(unit.getId()), null);
for (IInstallableUnit version : versions) {
modelUnit.getAvailableVersions().add(version.getVersion().getOriginal());
}
units.add(modelUnit);
}

return units;
IQueryResult<IInstallableUnit> result = repository.query(QueryUtil.ALL_UNITS, null);

return result.stream().map(iu -> new VersionedId(iu.getId(), iu.getVersion()));
} catch (URISyntaxException e) {
return Stream.empty();
} catch (Exception e) {
e.printStackTrace();
return Collections.emptyList();
ILog.get().error("Failed to fetch metadata of repository: " + repositoryLocation, e);
return Stream.empty();
}
}

Expand Down
Loading

0 comments on commit d141f1d

Please sign in to comment.