Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added ui/org.eclipse.pde.bnd.ui/icons/workspacerepo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.osgi.util.tracker.ServiceTracker;

import aQute.bnd.build.Workspace;
import aQute.bnd.build.WorkspaceLayout;
import aQute.bnd.memoize.Memoize;
import aQute.bnd.service.RegistryPlugin;
import aQute.bnd.service.RepositoryPlugin;
Expand All @@ -53,6 +54,7 @@ public class RepositoryUtils {
return tracker.orElse(null);
}, Objects::nonNull);
}


public static List<RepositoryPlugin> listRepositories(final Workspace localWorkspace, final boolean hideCache) {
if (localWorkspace == null) {
Expand All @@ -70,6 +72,14 @@ public static List<RepositoryPlugin> listRepositories(final Workspace localWorks
// Workspace bndWorkspace = Central.getWorkspaceIfPresent();
// if ((bndWorkspace == localWorkspace) && !bndWorkspace.isDefaultWorkspace())
// repos.add(Central.getWorkspaceRepository());

// TODO this is not perfect, because it is only working
// if you are selecting a bnd project. Would be better if bnd WorkspaceRepository is added always
// e.g. if there is at least one bnd project
if (WorkspaceLayout.BND == localWorkspace.getLayout() && !localWorkspace.isDefaultWorkspace()) {
repos.add(localWorkspace.getWorkspaceRepository());
Comment thread
chrisrueger marked this conversation as resolved.
}


// Add the repos from the provided workspace
for (RepositoryPlugin plugin : plugins) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -68,6 +69,11 @@ public class RepositoryTreeContentProvider implements ITreeContentProvider {

private String rawFilter = null;
private String wildcardFilter = null;
/**
* Number of filter results to keep per repo. This is to avoid memory leaks
* if you search with lots of different filter strings.
*/
private static final int MAX_CACHED_FILTER_RESULTS = 10;
private boolean showRepos = true;

private Requirement requirementFilter = null;
Expand Down Expand Up @@ -306,7 +312,8 @@ Object[] getRepositoryBundles(final RepositoryPlugin repoPlugin) {
* this node and the next time this method gets called the 'results'
* will be available in the cache
*/
Map<String, Object[]> listResults = repoPluginListResults.computeIfAbsent(repoPlugin, p -> new HashMap<>());
Map<String, Object[]> listResults = repoPluginListResults.computeIfAbsent(repoPlugin,
p -> createLRUMap(MAX_CACHED_FILTER_RESULTS));

result = listResults.get(wildcardFilter);

Expand Down Expand Up @@ -335,7 +342,7 @@ protected IStatus run(IProgressMonitor monitor) {
}

Map<String, Object[]> listResults = repoPluginListResults.computeIfAbsent(repoPlugin,
p -> new HashMap<>());
p -> createLRUMap(MAX_CACHED_FILTER_RESULTS));
listResults.put(wildcardFilter, jobresult);

Display.getDefault()
Expand All @@ -362,7 +369,7 @@ protected IStatus run(IProgressMonitor monitor) {

if (status != null && status.isOK()) {
Map<String, Object[]> fastResults = repoPluginListResults.computeIfAbsent(repoPlugin,
p -> new HashMap<>());
p -> createLRUMap(MAX_CACHED_FILTER_RESULTS));
result = fastResults.get(wildcardFilter);
} else {
Object[] loading = new Object[] {
Expand Down Expand Up @@ -392,4 +399,19 @@ private Object[] searchR5Repository(RepositoryPlugin repoPlugin, Repository osgi
result = resultSet.toArray();
return result;
}


// Define a LRU-like inner map (max n entries)
private static Map<String, Object[]> createLRUMap(int n) {
return new LinkedHashMap<String, Object[]>(n + 1, 1.0f, true) {
private static final long serialVersionUID = 1L;

@Override
protected boolean removeEldestEntry(Map.Entry<String, Object[]> eldest) {
// Auto-remove oldest when size > n
// but always keep the 'null' key which is '*'
return size() > n && eldest.getKey() != null;
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
*******************************************************************************/
package org.eclipse.pde.bnd.ui.model.repo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import aQute.bnd.service.RepositoryPlugin;
import aQute.bnd.service.repository.SearchableRepository;

Expand Down Expand Up @@ -42,4 +48,32 @@ Object[] getRepositoryBundles(RepositoryPlugin repo) {

return result;
}

public List<RepositoryBundleVersion> allRepoBundleVersions(final RepositoryPlugin rp) {
Object[] result = getChildren(rp);

List<RepositoryBundleVersion> allChildren = new ArrayList<>();
Queue<Object> queue = new LinkedList<>();

if (result != null) {
queue.addAll(Arrays.asList(result));
}

while (!queue.isEmpty()) {
Object currentChild = queue.poll();

if (currentChild instanceof RepositoryBundleVersion rpv) {
allChildren.add(rpv);
}
else if (currentChild instanceof RepositoryResourceElement rre) {
allChildren.add(rre.getRepositoryBundleVersion());
}

Object[] childrenOfChild = getChildren(currentChild);
if (childrenOfChild != null) {
queue.addAll(Arrays.asList(childrenOfChild));
}
}
return allChildren;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Iterator;
Expand Down Expand Up @@ -84,6 +85,7 @@
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerDropAdapter;
Expand Down Expand Up @@ -151,6 +153,8 @@
import aQute.bnd.build.Workspace;
import aQute.bnd.exceptions.Exceptions;
import aQute.bnd.http.HttpClient;
import aQute.bnd.osgi.resource.FilterParser.PackageExpression;
import aQute.bnd.osgi.resource.ResourceUtils;
import aQute.bnd.service.Actionable;
import aQute.bnd.service.Refreshable;
import aQute.bnd.service.Registry;
Expand Down Expand Up @@ -198,6 +202,9 @@
private final IObservableValue<String> workspaceName = new WritableValue<>();
private final IObservableValue<String> workspaceDescription = new WritableValue<>();

private Object[] lastExpandedElements;
private TreePath[] lastExpandedPaths;

@Override
public void createPartControl(final Composite parent) {
// CREATE CONTROLS
Expand Down Expand Up @@ -326,7 +333,7 @@
if (URLTransfer.getInstance()
.isSupportedType(getCurrentEvent().currentDataType)) {
try {
URL url = new URL((String) URLTransfer.getInstance()

Check warning on line 336 in ui/org.eclipse.pde.bnd.ui/src/org/eclipse/pde/bnd/ui/views/repository/RepositoriesView.java

View check run for this annotation

Jenkins - eclipse-pde / Compiler

Deprecation

NORMAL: The constructor URL(String) is deprecated since version 20
.nativeToJava(getCurrentEvent().currentDataType));

File tmp = File.createTempFile("dwnl", ".jar");
Expand Down Expand Up @@ -601,11 +608,28 @@
}

private void updatedFilter(String filterString) {
contentProvider.setFilter(filterString);
viewer.refresh();
if (filterString != null) {
viewer.expandToLevel(2);
}
viewer.getTree()
.setRedraw(false);

try {
if (filterString == null || filterString.isEmpty()) {
// Restore previous state when clearing filter
contentProvider.setFilter(null);
viewer.refresh(); // Required to clear filter
restoreExpansionState();
viewer.refresh();
} else {
// Save state before applying new filter
saveExpansionState();
contentProvider.setFilter(filterString);
viewer.refresh();
viewer.expandToLevel(2);
}

} finally {
viewer.getTree()
.setRedraw(true);
}
}

void createActions() {
Expand Down Expand Up @@ -1209,10 +1233,78 @@

if ((act instanceof Repository) || (act instanceof RepositoryPlugin)) {
hmenu.add(createContextMenueCopyInfoRepo(act, rp, clipboard));
hmenu.add(createContextMenueCopyBundlesWithSelfImports(act, rp, clipboard));
}

}


private HierarchicalLabel<Action> createContextMenueCopyBundlesWithSelfImports(Actionable act, final RepositoryPlugin rp,
final Clipboard clipboard) {
return new HierarchicalLabel<Action>("Copy to clipboard :: Bundles with substitution packages (self-imports)",
(label) -> createAction(label.getLeaf(),
"Add list of bundles containing packages which are imported and exported in their Manifest.", true,
false, rp, () -> {

final StringBuilder sb = new StringBuilder(
"Shows list of bundles in the repository '" + rp.getName()
+ "' containing substitution packages / self-imports (i.e. same package imported and exported) in their Manifest. \n"
+ "Note: a missing version range can cause wiring / resolution problems.\n"
+ "See https://docs.osgi.org/specification/osgi.core/8.0.0/framework.module.html#i3238802 "
+ "and https://docs.osgi.org/specification/osgi.core/8.0.0/framework.module.html#framework.module-import.export.same.package "
+ "for more information."
+ "\n\n");

for (RepositoryBundleVersion rpv : contentProvider.allRepoBundleVersions(rp)) {
org.osgi.resource.Resource r = rpv.getResource();
Collection<PackageExpression> selfImports = ResourceUtils
.getSubstitutionPackages(r);

if (!selfImports.isEmpty()) {
long numWithoutRange = selfImports.stream()
.filter(pckExp -> pckExp.getRangeExpression() == null)
.count();

// Main package information
sb.append(r.toString())
.append("\n");
sb.append(" Substitution packages: ")
.append(selfImports.size());

// Additional information about packages without
// version range
if (numWithoutRange > 0) {
sb.append(" (")
.append(numWithoutRange)
.append(" without version range)");
}
sb.append("\n");

// List of substitution packages
sb.append(" [\n");
for (PackageExpression pckExp : selfImports) {
sb.append(" ")
.append(pckExp.toString())
.append(",\n");
}
// Remove the last comma and newline
if (!selfImports.isEmpty()) {
sb.setLength(sb.length() - 2);
}
sb.append("\n ]\n\n");
}

}

if (sb.isEmpty()) {
clipboard.copy("-Empty-");
} else {
clipboard.copy(sb.toString());
}

}));
}

private HierarchicalLabel<Action> createContextMenueCopyInfoRepo(Actionable act, final RepositoryPlugin rp,
final Clipboard clipboard) {
return new HierarchicalLabel<Action>("Copy to clipboard :: Copy info", (label) -> createAction(label.getLeaf(),
Expand Down Expand Up @@ -1330,6 +1422,21 @@
}
}

private void saveExpansionState() {
lastExpandedElements = viewer.getExpandedElements();
lastExpandedPaths = viewer.getExpandedTreePaths();
}

private void restoreExpansionState() {
if (lastExpandedElements != null) {
viewer.setExpandedElements(lastExpandedElements);
}
if (lastExpandedPaths != null) {
viewer.setExpandedTreePaths(lastExpandedPaths);
}
}


@Override
public Workspace getWorkspace() {
return this.workspace;
Expand Down
Loading