mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
Refactored plugin configuration methods
This commit is contained in:
parent
5719632656
commit
f5f71426d9
17 changed files with 274 additions and 176 deletions
|
@ -30,7 +30,7 @@ import ghidra.framework.model.Project;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.framework.options.ToolOptions;
|
import ghidra.framework.options.ToolOptions;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.framework.plugintool.util.PluginClassManager;
|
import ghidra.framework.plugintool.util.PluginsConfiguration;
|
||||||
import ghidra.program.database.ProgramBuilder;
|
import ghidra.program.database.ProgramBuilder;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||||
|
@ -413,8 +413,8 @@ public class AnalyzeAllOpenProgramsTaskTest extends AbstractGhidraHeadedIntegrat
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PluginClassManager getPluginClassManager() {
|
public PluginsConfiguration createPluginsConfigurations() {
|
||||||
return null;
|
return null; // prevent slow class loading
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.framework.main;
|
||||||
|
|
||||||
|
import ghidra.framework.plugintool.Plugin;
|
||||||
|
import ghidra.framework.plugintool.util.PluginsConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A configuration that only includes {@link ApplicationLevelPlugin} plugins.
|
||||||
|
*/
|
||||||
|
class ApplicationLevelPluginsConfiguration extends PluginsConfiguration {
|
||||||
|
@Override
|
||||||
|
protected boolean accepts(Class<? extends Plugin> c) {
|
||||||
|
return ApplicationLevelPlugin.class.isAssignableFrom(c);
|
||||||
|
}
|
||||||
|
}
|
|
@ -131,7 +131,6 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||||
|
|
||||||
private WindowListener windowListener;
|
private WindowListener windowListener;
|
||||||
private DockingAction configureToolAction;
|
private DockingAction configureToolAction;
|
||||||
private PluginClassManager pluginClassManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new Ghidra Project Window.
|
* Construct a new Ghidra Project Window.
|
||||||
|
@ -190,11 +189,8 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PluginClassManager getPluginClassManager() {
|
protected PluginsConfiguration createPluginsConfigurations() {
|
||||||
if (pluginClassManager == null) {
|
return new ApplicationLevelPluginsConfiguration();
|
||||||
pluginClassManager = new PluginClassManager(ApplicationLevelPlugin.class, null);
|
|
||||||
}
|
|
||||||
return pluginClassManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void selectFiles(Set<DomainFile> files) {
|
public void selectFiles(Set<DomainFile> files) {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -17,9 +16,9 @@
|
||||||
package ghidra.framework.main;
|
package ghidra.framework.main;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marker interface for plugins that only get constructed programatically for specific purposes.
|
* Marker interface for plugins that only get constructed programmatically for specific purposes.
|
||||||
* Plugins that implement this interface should never be added via the config GUIs.
|
* Plugins that implement this interface should never be added via the config GUIs.
|
||||||
*/
|
*/
|
||||||
public interface ProgramaticUseOnly {
|
public interface ProgramaticUseOnly {
|
||||||
|
// marker interface
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,13 +20,13 @@ import java.util.List;
|
||||||
import ghidra.framework.plugintool.util.*;
|
import ghidra.framework.plugintool.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default plugin package provider that uses the {@link PluginClassManager} to supply packages
|
* The default plugin package provider that uses the {@link PluginsConfiguration} to supply packages
|
||||||
*/
|
*/
|
||||||
public class DeafultPluginPackagingProvider implements PluginPackagingProvider {
|
public class DeafultPluginPackagingProvider implements PluginPackagingProvider {
|
||||||
|
|
||||||
private PluginClassManager pluginClassManager;
|
private PluginsConfiguration pluginClassManager;
|
||||||
|
|
||||||
DeafultPluginPackagingProvider(PluginClassManager pluginClassManager) {
|
DeafultPluginPackagingProvider(PluginsConfiguration pluginClassManager) {
|
||||||
this.pluginClassManager = pluginClassManager;
|
this.pluginClassManager = pluginClassManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ package ghidra.framework.plugintool;
|
||||||
|
|
||||||
import ghidra.framework.main.AppInfo;
|
import ghidra.framework.main.AppInfo;
|
||||||
import ghidra.framework.model.Project;
|
import ghidra.framework.model.Project;
|
||||||
import ghidra.framework.plugintool.util.PluginClassManager;
|
import ghidra.framework.plugintool.util.PluginsConfiguration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PluginTool that is used by the Merge process to resolve conflicts
|
* PluginTool that is used by the Merge process to resolve conflicts
|
||||||
|
@ -44,7 +44,7 @@ public class ModalPluginTool extends PluginTool {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PluginClassManager getPluginClassManager() {
|
public PluginsConfiguration createPluginsConfigurations() {
|
||||||
return null;
|
return null; // no need to load plugins
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class PluginConfigurationModel {
|
||||||
|
|
||||||
public PluginConfigurationModel(PluginTool tool) {
|
public PluginConfigurationModel(PluginTool tool) {
|
||||||
this(new DefaultPluginInstaller(tool),
|
this(new DefaultPluginInstaller(tool),
|
||||||
new DeafultPluginPackagingProvider(tool.getPluginClassManager()));
|
new DeafultPluginPackagingProvider(tool.getPluginsConfiguration()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public PluginConfigurationModel(PluginInstaller pluginInstaller,
|
public PluginConfigurationModel(PluginInstaller pluginInstaller,
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.jdom.Element;
|
import org.jdom.Element;
|
||||||
|
|
||||||
|
import ghidra.framework.main.UtilityPluginPackage;
|
||||||
import ghidra.framework.model.DomainFile;
|
import ghidra.framework.model.DomainFile;
|
||||||
import ghidra.framework.model.DomainObject;
|
import ghidra.framework.model.DomainObject;
|
||||||
import ghidra.framework.options.SaveState;
|
import ghidra.framework.options.SaveState;
|
||||||
|
@ -33,15 +34,40 @@ import ghidra.util.classfinder.ClassSearcher;
|
||||||
import ghidra.util.exception.MultipleCauses;
|
import ghidra.util.exception.MultipleCauses;
|
||||||
|
|
||||||
class PluginManager {
|
class PluginManager {
|
||||||
static final Logger log = LogManager.getLogger(PluginManager.class);
|
private static final Logger log = LogManager.getLogger(PluginManager.class);
|
||||||
|
|
||||||
|
private PluginsConfiguration pluginsConfiguration;
|
||||||
private List<Plugin> pluginList = new ArrayList<>();
|
private List<Plugin> pluginList = new ArrayList<>();
|
||||||
private PluginTool tool;
|
private PluginTool tool;
|
||||||
private ServiceManager serviceMgr;
|
private ServiceManager serviceMgr;
|
||||||
|
|
||||||
PluginManager(PluginTool tool, ServiceManager serviceMgr) {
|
PluginManager(PluginTool tool, ServiceManager serviceMgr,
|
||||||
|
PluginsConfiguration pluginsConfiguration) {
|
||||||
this.tool = tool;
|
this.tool = tool;
|
||||||
this.serviceMgr = serviceMgr;
|
this.serviceMgr = serviceMgr;
|
||||||
|
this.pluginsConfiguration = pluginsConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
void installUtilityPlugins() throws PluginException {
|
||||||
|
|
||||||
|
PluginPackage utilityPackage = PluginPackage.getPluginPackage(UtilityPluginPackage.NAME);
|
||||||
|
List<PluginDescription> descriptions =
|
||||||
|
pluginsConfiguration.getPluginDescriptions(utilityPackage);
|
||||||
|
if (descriptions == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> classNames = new HashSet<>();
|
||||||
|
for (PluginDescription description : descriptions) {
|
||||||
|
String pluginClass = description.getPluginClass().getName();
|
||||||
|
classNames.add(pluginClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
addPlugins(classNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginsConfiguration getPluginsConfiguration() {
|
||||||
|
return pluginsConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean acceptData(DomainFile[] data) {
|
boolean acceptData(DomainFile[] data) {
|
||||||
|
@ -72,7 +98,7 @@ class PluginManager {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dispose() {
|
void dispose() {
|
||||||
for (Iterator<Plugin> it = pluginList.iterator(); it.hasNext();) {
|
for (Iterator<Plugin> it = pluginList.iterator(); it.hasNext();) {
|
||||||
Plugin plugin = it.next();
|
Plugin plugin = it.next();
|
||||||
plugin.cleanup();
|
plugin.cleanup();
|
||||||
|
@ -255,15 +281,14 @@ class PluginManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveToXml(Element root, boolean includeConfigState) {
|
void saveToXml(Element root, boolean includeConfigState) {
|
||||||
PluginClassManager pluginClassManager = tool.getPluginClassManager();
|
|
||||||
pluginClassManager.addXmlElementsForPlugins(root, pluginList);
|
pluginsConfiguration.savePluginsToXml(root, pluginList);
|
||||||
|
|
||||||
if (!includeConfigState) {
|
if (!includeConfigState) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveState saveState = new SaveState("PLUGIN_STATE");
|
SaveState saveState = new SaveState("PLUGIN_STATE");
|
||||||
|
|
||||||
Iterator<Plugin> it = pluginList.iterator();
|
Iterator<Plugin> it = pluginList.iterator();
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
Plugin p = it.next();
|
Plugin p = it.next();
|
||||||
|
@ -279,8 +304,8 @@ class PluginManager {
|
||||||
|
|
||||||
void restorePluginsFromXml(Element root) throws PluginException {
|
void restorePluginsFromXml(Element root) throws PluginException {
|
||||||
boolean isOld = isOldToolConfig(root);
|
boolean isOld = isOldToolConfig(root);
|
||||||
Collection<String> classNames =
|
Collection<String> classNames = isOld ? getPluginClassNamesFromOldXml(root)
|
||||||
isOld ? getPluginClassNamesFromOldXml(root) : getPluginClassNamesToLoad(root);
|
: pluginsConfiguration.getPluginClassNames(root);
|
||||||
Map<String, SaveState> map = isOld ? getPluginSavedStates(root, "PLUGIN")
|
Map<String, SaveState> map = isOld ? getPluginSavedStates(root, "PLUGIN")
|
||||||
: getPluginSavedStates(root, "PLUGIN_STATE");
|
: getPluginSavedStates(root, "PLUGIN_STATE");
|
||||||
|
|
||||||
|
@ -324,19 +349,14 @@ class PluginManager {
|
||||||
String className = elem.getAttributeValue("CLASS");
|
String className = elem.getAttributeValue("CLASS");
|
||||||
classNames.add(className);
|
classNames.add(className);
|
||||||
}
|
}
|
||||||
PluginClassManager pluginClassManager = tool.getPluginClassManager();
|
|
||||||
return pluginClassManager.fillInPackageClasses(classNames);
|
return pluginsConfiguration.getPluginNamesByCurrentPackage(classNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isOldToolConfig(Element root) {
|
private boolean isOldToolConfig(Element root) {
|
||||||
return root.getChild("PLUGIN") != null;
|
return root.getChild("PLUGIN") != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<String> getPluginClassNamesToLoad(Element root) {
|
|
||||||
PluginClassManager pluginClassManager = tool.getPluginClassManager();
|
|
||||||
return pluginClassManager.getPluginClasses(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restore the data state from the given XML element.
|
* Restore the data state from the given XML element.
|
||||||
* @param root XML element containing plugins' data state
|
* @param root XML element containing plugins' data state
|
||||||
|
@ -465,8 +485,9 @@ class PluginManager {
|
||||||
// TODO: this following loop is searching for any non-loaded Plugin that implements
|
// TODO: this following loop is searching for any non-loaded Plugin that implements
|
||||||
// the required service class interface.
|
// the required service class interface.
|
||||||
// This doesn't seem exactly right as a Service implementation shouldn't
|
// This doesn't seem exactly right as a Service implementation shouldn't
|
||||||
// be automagically pulled in and instantiated UNLESS it was specified as the "defaultProvider",
|
// be automagically pulled in and instantiated UNLESS it was specified as the
|
||||||
// which we've already checked for in the previous PluginUtils.getDefaultProviderForServiceClass().
|
// "defaultProvider", which we've already checked for in the previous
|
||||||
|
// PluginUtils.getDefaultProviderForServiceClass().
|
||||||
// TODO: this also should be filtered by the PluginClassManager so we don't
|
// TODO: this also should be filtered by the PluginClassManager so we don't
|
||||||
// pull in classes that have been excluded.
|
// pull in classes that have been excluded.
|
||||||
for (Class<? extends Plugin> pc : ClassSearcher.getClasses(Plugin.class)) {
|
for (Class<? extends Plugin> pc : ClassSearcher.getClasses(Plugin.class)) {
|
||||||
|
|
|
@ -45,7 +45,8 @@ import ghidra.framework.OperatingSystem;
|
||||||
import ghidra.framework.Platform;
|
import ghidra.framework.Platform;
|
||||||
import ghidra.framework.cmd.BackgroundCommand;
|
import ghidra.framework.cmd.BackgroundCommand;
|
||||||
import ghidra.framework.cmd.Command;
|
import ghidra.framework.cmd.Command;
|
||||||
import ghidra.framework.main.*;
|
import ghidra.framework.main.AppInfo;
|
||||||
|
import ghidra.framework.main.UserAgreementDialog;
|
||||||
import ghidra.framework.model.*;
|
import ghidra.framework.model.*;
|
||||||
import ghidra.framework.options.*;
|
import ghidra.framework.options.*;
|
||||||
import ghidra.framework.plugintool.dialog.ExtensionTableProvider;
|
import ghidra.framework.plugintool.dialog.ExtensionTableProvider;
|
||||||
|
@ -175,7 +176,7 @@ public abstract class PluginTool extends AbstractDockingTool {
|
||||||
eventMgr = new EventManager(this);
|
eventMgr = new EventManager(this);
|
||||||
serviceMgr = new ServiceManager();
|
serviceMgr = new ServiceManager();
|
||||||
installServices();
|
installServices();
|
||||||
pluginMgr = new PluginManager(this, serviceMgr);
|
pluginMgr = new PluginManager(this, serviceMgr, createPluginsConfigurations());
|
||||||
dialogMgr = new DialogManager(this);
|
dialogMgr = new DialogManager(this);
|
||||||
initActions();
|
initActions();
|
||||||
initOptions();
|
initOptions();
|
||||||
|
@ -192,7 +193,13 @@ public abstract class PluginTool extends AbstractDockingTool {
|
||||||
// non-public constructor for stub subclasses
|
// non-public constructor for stub subclasses
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract PluginClassManager getPluginClassManager();
|
protected PluginsConfiguration createPluginsConfigurations() {
|
||||||
|
return new DefaultPluginsConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected PluginsConfiguration getPluginsConfiguration() {
|
||||||
|
return pluginMgr.getPluginsConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method exists here, as opposed to inline in the constructor, so that subclasses can
|
* This method exists here, as opposed to inline in the constructor, so that subclasses can
|
||||||
|
@ -233,21 +240,15 @@ public abstract class PluginTool extends AbstractDockingTool {
|
||||||
*/
|
*/
|
||||||
protected void installUtilityPlugins() {
|
protected void installUtilityPlugins() {
|
||||||
|
|
||||||
PluginClassManager classManager = getPluginClassManager();
|
|
||||||
PluginPackage utilityPackage = PluginPackage.getPluginPackage(UtilityPluginPackage.NAME);
|
|
||||||
List<PluginDescription> descriptions = classManager.getPluginDescriptions(utilityPackage);
|
|
||||||
|
|
||||||
Set<String> classNames = new HashSet<>();
|
|
||||||
if (descriptions == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (PluginDescription description : descriptions) {
|
|
||||||
String pluginClass = description.getPluginClass().getName();
|
|
||||||
classNames.add(pluginClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
addPlugins(classNames);
|
checkedRunSwingNow(() -> {
|
||||||
|
try {
|
||||||
|
pluginMgr.installUtilityPlugins();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
setConfigChanged(true);
|
||||||
|
}
|
||||||
|
}, PluginException.class);
|
||||||
}
|
}
|
||||||
catch (PluginException e) {
|
catch (PluginException e) {
|
||||||
Msg.showError(this, null, "Error Adding Utility Plugins",
|
Msg.showError(this, null, "Error Adding Utility Plugins",
|
||||||
|
|
|
@ -23,12 +23,12 @@ import docking.action.*;
|
||||||
import docking.tool.ToolConstants;
|
import docking.tool.ToolConstants;
|
||||||
import ghidra.framework.OperatingSystem;
|
import ghidra.framework.OperatingSystem;
|
||||||
import ghidra.framework.Platform;
|
import ghidra.framework.Platform;
|
||||||
import ghidra.framework.plugintool.util.PluginClassManager;
|
import ghidra.framework.plugintool.util.PluginsConfiguration;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
public class StandAlonePluginTool extends PluginTool {
|
public class StandAlonePluginTool extends PluginTool {
|
||||||
|
|
||||||
private PluginClassManager pluginClassManager;
|
private PluginsConfiguration pluginClassManager;
|
||||||
private DockingAction configureToolAction;
|
private DockingAction configureToolAction;
|
||||||
private final GenericStandAloneApplication app;
|
private final GenericStandAloneApplication app;
|
||||||
private final String name;
|
private final String name;
|
||||||
|
@ -39,14 +39,6 @@ public class StandAlonePluginTool extends PluginTool {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public PluginClassManager getPluginClassManager() {
|
|
||||||
if (pluginClassManager == null) {
|
|
||||||
pluginClassManager = new PluginClassManager(Plugin.class, null);
|
|
||||||
}
|
|
||||||
return pluginClassManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addExitAction() {
|
public void addExitAction() {
|
||||||
DockingAction exitAction = new DockingAction("Exit", ToolConstants.TOOL_OWNER) {
|
DockingAction exitAction = new DockingAction("Exit", ToolConstants.TOOL_OWNER) {
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.framework.plugintool.util;
|
||||||
|
|
||||||
|
import ghidra.framework.plugintool.Plugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A configuration that includes all plugins on the classpath.
|
||||||
|
*/
|
||||||
|
public class DefaultPluginsConfiguration extends PluginsConfiguration {
|
||||||
|
@Override
|
||||||
|
protected boolean accepts(Class<? extends Plugin> pluginClass) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,48 +33,6 @@ import ghidra.util.exception.AssertException;
|
||||||
*/
|
*/
|
||||||
public class PluginUtils {
|
public class PluginUtils {
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds all {@link PluginDescription} objects that match a given set of plugin classes. This
|
|
||||||
* effectively tells the caller which of the given plugins have been loaded by the class loader.
|
|
||||||
* <p>
|
|
||||||
* eg: If the list of plugin classes contains the class "FooPlugin.class", this method
|
|
||||||
* will search the {@link PluginConfigurationModel} for any plugin with the name "FooPlugin" and
|
|
||||||
* return its {@link PluginDescription}.
|
|
||||||
* <p>
|
|
||||||
* Note that this method does not take path/package information into account when finding
|
|
||||||
* plugins; in the example above, if there is more than one plugin with the name "FooPlugin",
|
|
||||||
* only one will be found (the one found is not guaranteed to be the first).
|
|
||||||
*
|
|
||||||
* @param tool the current tool
|
|
||||||
* @param plugins the list of plugin classes to search for
|
|
||||||
* @return list of plugin descriptions
|
|
||||||
*/
|
|
||||||
public static List<PluginDescription> getPluginDescriptions(PluginTool tool,
|
|
||||||
List<Class<?>> plugins) {
|
|
||||||
|
|
||||||
// First define the list of plugin descriptions to return
|
|
||||||
List<PluginDescription> retPlugins = new ArrayList<>();
|
|
||||||
|
|
||||||
// Get all plugins that have been loaded
|
|
||||||
PluginClassManager pluginClassManager = tool.getPluginClassManager();
|
|
||||||
List<PluginDescription> allPluginDescriptions =
|
|
||||||
pluginClassManager.getManagedPluginDescriptions();
|
|
||||||
|
|
||||||
// see if an entry exists in the list of all loaded plugins
|
|
||||||
for (Class<?> plugin : plugins) {
|
|
||||||
String pluginName = plugin.getSimpleName();
|
|
||||||
|
|
||||||
Optional<PluginDescription> desc = allPluginDescriptions.stream()
|
|
||||||
.filter(d -> (pluginName.equals(d.getName())))
|
|
||||||
.findAny();
|
|
||||||
if (desc.isPresent()) {
|
|
||||||
retPlugins.add(desc.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return retPlugins;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds all plugin classes loaded from a given set of extensions.
|
* Finds all plugin classes loaded from a given set of extensions.
|
||||||
*
|
*
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.framework.plugintool.util;
|
package ghidra.framework.plugintool.util;
|
||||||
|
|
||||||
|
import static java.util.function.Predicate.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
@ -25,30 +27,33 @@ import ghidra.framework.plugintool.Plugin;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.classfinder.ClassSearcher;
|
import ghidra.util.classfinder.ClassSearcher;
|
||||||
|
|
||||||
public class PluginClassManager {
|
/**
|
||||||
|
* This class maintains a collection of all plugin classes that are acceptable for a given tool
|
||||||
|
* type. Simple applications with only one plugin type can use the
|
||||||
|
* {@link DefaultPluginsConfiguration}. More complex tools can support a subset of the available
|
||||||
|
* plugins. Those tools should create custom subclasses for each tool type, that filter out plugins
|
||||||
|
* that are not appropriate for that tool type.
|
||||||
|
*/
|
||||||
|
public abstract class PluginsConfiguration {
|
||||||
|
|
||||||
private Map<PluginPackage, List<PluginDescription>> packageMap = new HashMap<>();
|
private Map<PluginPackage, List<PluginDescription>> descriptionsByPackage = new HashMap<>();
|
||||||
|
private Map<String, PluginDescription> descriptionsByName = new HashMap<>();
|
||||||
|
|
||||||
private Map<String, PluginDescription> pluginClassMap = new HashMap<>();
|
protected PluginsConfiguration() {
|
||||||
|
populatePluginDescriptionMaps();
|
||||||
public PluginClassManager(Class<?> filterClass, Class<?> exclusionClass) {
|
|
||||||
populatePluginDescriptionMaps(filterClass, exclusionClass);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PluginDescription getPluginDescription(String className) {
|
protected abstract boolean accepts(Class<? extends Plugin> pluginClass);
|
||||||
return pluginClassMap.get(className);
|
|
||||||
|
private Predicate<Class<? extends Plugin>> createFilter() {
|
||||||
|
Predicate<Class<? extends Plugin>> ignore = ProgramaticUseOnly.class::isAssignableFrom;
|
||||||
|
return not(ignore).and(c -> accepts(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populatePluginDescriptionMaps(Class<?> localFilterClass,
|
private void populatePluginDescriptionMaps() {
|
||||||
Class<?> localExclusionClass) {
|
|
||||||
|
|
||||||
Predicate<Class<? extends Plugin>> myClassFilter =
|
Predicate<Class<? extends Plugin>> classFilter = createFilter();
|
||||||
c -> (localFilterClass == null || localFilterClass.isAssignableFrom(c)) &&
|
List<Class<? extends Plugin>> classes = ClassSearcher.getClasses(Plugin.class, classFilter);
|
||||||
(localExclusionClass == null || !localExclusionClass.isAssignableFrom(c)) &&
|
|
||||||
!ProgramaticUseOnly.class.isAssignableFrom(c);
|
|
||||||
|
|
||||||
List<Class<? extends Plugin>> classes =
|
|
||||||
ClassSearcher.getClasses(Plugin.class, myClassFilter);
|
|
||||||
|
|
||||||
for (Class<? extends Plugin> pluginClass : classes) {
|
for (Class<? extends Plugin> pluginClass : classes) {
|
||||||
if (!PluginUtils.isValidPluginClass(pluginClass)) {
|
if (!PluginUtils.isValidPluginClass(pluginClass)) {
|
||||||
|
@ -57,16 +62,21 @@ public class PluginClassManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginDescription pd = PluginDescription.getPluginDescription(pluginClass);
|
PluginDescription pd = PluginDescription.getPluginDescription(pluginClass);
|
||||||
pluginClassMap.put(pluginClass.getName(), pd);
|
descriptionsByName.put(pluginClass.getName(), pd);
|
||||||
|
|
||||||
PluginPackage pluginPackage = pd.getPluginPackage();
|
PluginPackage pluginPackage = pd.getPluginPackage();
|
||||||
List<PluginDescription> list =
|
List<PluginDescription> list =
|
||||||
packageMap.computeIfAbsent(pluginPackage, (k) -> new ArrayList<>());
|
descriptionsByPackage.computeIfAbsent(pluginPackage, (k) -> new ArrayList<>());
|
||||||
list.add(pd);
|
list.add(pd);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addXmlElementsForPlugins(Element root, List<Plugin> plugins) {
|
public PluginDescription getPluginDescription(String className) {
|
||||||
|
return descriptionsByName.get(className);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void savePluginsToXml(Element root, List<Plugin> plugins) {
|
||||||
Map<PluginPackage, List<Plugin>> pluginPackageMap = buildPluginPackageMap(plugins);
|
Map<PluginPackage, List<Plugin>> pluginPackageMap = buildPluginPackageMap(plugins);
|
||||||
for (PluginPackage pluginPackage : pluginPackageMap.keySet()) {
|
for (PluginPackage pluginPackage : pluginPackageMap.keySet()) {
|
||||||
root.addContent(getPackageElement(pluginPackage, pluginPackageMap.get(pluginPackage)));
|
root.addContent(getPackageElement(pluginPackage, pluginPackageMap.get(pluginPackage)));
|
||||||
|
@ -76,7 +86,7 @@ public class PluginClassManager {
|
||||||
private Element getPackageElement(PluginPackage pluginPackage, List<Plugin> pluginList) {
|
private Element getPackageElement(PluginPackage pluginPackage, List<Plugin> pluginList) {
|
||||||
Element packageElement = new Element("PACKAGE");
|
Element packageElement = new Element("PACKAGE");
|
||||||
packageElement.setAttribute("NAME", pluginPackage.getName());
|
packageElement.setAttribute("NAME", pluginPackage.getName());
|
||||||
List<PluginDescription> pluginDescriptions = packageMap.get(pluginPackage);
|
List<PluginDescription> pluginDescriptions = descriptionsByPackage.get(pluginPackage);
|
||||||
|
|
||||||
Set<String> includedPluginClasses = new HashSet<>();
|
Set<String> includedPluginClasses = new HashSet<>();
|
||||||
for (Plugin plugin : pluginList) {
|
for (Plugin plugin : pluginList) {
|
||||||
|
@ -120,7 +130,8 @@ public class PluginClassManager {
|
||||||
private Map<PluginPackage, List<Plugin>> buildPluginPackageMap(List<Plugin> plugins) {
|
private Map<PluginPackage, List<Plugin>> buildPluginPackageMap(List<Plugin> plugins) {
|
||||||
Map<PluginPackage, List<Plugin>> pluginPackageMap = new HashMap<>();
|
Map<PluginPackage, List<Plugin>> pluginPackageMap = new HashMap<>();
|
||||||
for (Plugin plugin : plugins) {
|
for (Plugin plugin : plugins) {
|
||||||
PluginDescription pluginDescription = pluginClassMap.get(plugin.getClass().getName());
|
PluginDescription pluginDescription =
|
||||||
|
descriptionsByName.get(plugin.getClass().getName());
|
||||||
if (pluginDescription == null) {
|
if (pluginDescription == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -138,41 +149,42 @@ public class PluginClassManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to convert an old style tool XML file by adding in classes in the same packages as
|
* Used to convert an old style tool XML file by mapping the given class names to plugin
|
||||||
* those that were named specifically in the XML file
|
* packages and then adding <b>all</b> plugins in that package. This has the effect of pulling
|
||||||
|
* in more plugin classes than were originally specified in the tool xml.
|
||||||
|
*
|
||||||
* @param classNames the list of classNames from from the old XML file
|
* @param classNames the list of classNames from from the old XML file
|
||||||
* @return the adjusted class names
|
* @return the adjusted set of plugin class names
|
||||||
*/
|
*/
|
||||||
public Set<String> fillInPackageClasses(List<String> classNames) {
|
public Set<String> getPluginNamesByCurrentPackage(List<String> classNames) {
|
||||||
Set<PluginPackage> packages = new HashSet<>();
|
Set<PluginPackage> packages = new HashSet<>();
|
||||||
Set<String> adjustedClassNames = new HashSet<>();
|
Set<String> adjustedClassNames = new HashSet<>();
|
||||||
|
|
||||||
for (String className : classNames) {
|
for (String className : classNames) {
|
||||||
PluginDescription pluginDescription = pluginClassMap.get(className);
|
PluginDescription pd = descriptionsByName.get(className);
|
||||||
if (pluginDescription != null) {
|
if (pd == null) {
|
||||||
if (pluginDescription.getStatus() == PluginStatus.RELEASED) {
|
continue; // plugin no longer in tool
|
||||||
packages.add(pluginDescription.getPluginPackage());
|
}
|
||||||
|
|
||||||
|
if (pd.getStatus() == PluginStatus.RELEASED) {
|
||||||
|
packages.add(pd.getPluginPackage());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
adjustedClassNames.add(className);
|
adjustedClassNames.add(className);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
for (PluginPackage pluginPackage : packages) {
|
for (PluginPackage pluginPackage : packages) {
|
||||||
List<PluginDescription> list = packageMap.get(pluginPackage);
|
List<PluginDescription> packageDescriptions = descriptionsByPackage.get(pluginPackage);
|
||||||
for (PluginDescription pluginDescription : list) {
|
for (PluginDescription pd : packageDescriptions) {
|
||||||
if (pluginDescription.getStatus() != PluginStatus.RELEASED) {
|
adjustedClassNames.add(pd.getPluginClass().getName());
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String name = pluginDescription.getPluginClass().getName();
|
|
||||||
adjustedClassNames.add(name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return adjustedClassNames;
|
return adjustedClassNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<String> getPluginClasses(Element element) {
|
public Set<String> getPluginClassNames(Element element) {
|
||||||
|
|
||||||
Set<String> classNames = new HashSet<>();
|
Set<String> classNames = new HashSet<>();
|
||||||
List<?> children = element.getChildren("PACKAGE");
|
List<?> children = element.getChildren("PACKAGE");
|
||||||
|
@ -206,7 +218,8 @@ public class PluginClassManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginPackage pluginPackage = PluginPackage.getPluginPackage(packageName);
|
PluginPackage pluginPackage = PluginPackage.getPluginPackage(packageName);
|
||||||
List<PluginDescription> pluginDescriptionList = packageMap.get(pluginPackage);
|
List<PluginDescription> pluginDescriptionList =
|
||||||
|
descriptionsByPackage.get(pluginPackage);
|
||||||
if (pluginDescriptionList == null) {
|
if (pluginDescriptionList == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -236,13 +249,13 @@ public class PluginClassManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PluginPackage> getPluginPackages() {
|
public List<PluginPackage> getPluginPackages() {
|
||||||
List<PluginPackage> list = new ArrayList<>(packageMap.keySet());
|
List<PluginPackage> list = new ArrayList<>(descriptionsByPackage.keySet());
|
||||||
Collections.sort(list);
|
Collections.sort(list);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PluginDescription> getPluginDescriptions(PluginPackage pluginPackage) {
|
public List<PluginDescription> getPluginDescriptions(PluginPackage pluginPackage) {
|
||||||
List<PluginDescription> list = packageMap.get(pluginPackage);
|
List<PluginDescription> list = descriptionsByPackage.get(pluginPackage);
|
||||||
List<PluginDescription> stableList = new ArrayList<>();
|
List<PluginDescription> stableList = new ArrayList<>();
|
||||||
for (PluginDescription pluginDescription : list) {
|
for (PluginDescription pluginDescription : list) {
|
||||||
if (pluginDescription.getStatus() == PluginStatus.UNSTABLE ||
|
if (pluginDescription.getStatus() == PluginStatus.UNSTABLE ||
|
||||||
|
@ -256,7 +269,7 @@ public class PluginClassManager {
|
||||||
|
|
||||||
public List<PluginDescription> getUnstablePluginDescriptions() {
|
public List<PluginDescription> getUnstablePluginDescriptions() {
|
||||||
List<PluginDescription> unstablePlugins = new ArrayList<>();
|
List<PluginDescription> unstablePlugins = new ArrayList<>();
|
||||||
for (PluginDescription pluginDescription : pluginClassMap.values()) {
|
for (PluginDescription pluginDescription : descriptionsByName.values()) {
|
||||||
if (pluginDescription.getStatus() == PluginStatus.UNSTABLE) {
|
if (pluginDescription.getStatus() == PluginStatus.UNSTABLE) {
|
||||||
unstablePlugins.add(pluginDescription);
|
unstablePlugins.add(pluginDescription);
|
||||||
}
|
}
|
||||||
|
@ -266,7 +279,7 @@ public class PluginClassManager {
|
||||||
|
|
||||||
public List<PluginDescription> getManagedPluginDescriptions() {
|
public List<PluginDescription> getManagedPluginDescriptions() {
|
||||||
ArrayList<PluginDescription> nonHiddenPlugins = new ArrayList<>();
|
ArrayList<PluginDescription> nonHiddenPlugins = new ArrayList<>();
|
||||||
for (PluginDescription pluginDescription : pluginClassMap.values()) {
|
for (PluginDescription pluginDescription : descriptionsByName.values()) {
|
||||||
if (pluginDescription.getStatus() == PluginStatus.HIDDEN) {
|
if (pluginDescription.getStatus() == PluginStatus.HIDDEN) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.framework.project.tool;
|
||||||
|
|
||||||
|
import ghidra.framework.main.ApplicationLevelOnlyPlugin;
|
||||||
|
import ghidra.framework.plugintool.Plugin;
|
||||||
|
import ghidra.framework.plugintool.util.PluginsConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A configuration that allows all general plugins and application plugins. Plugins that may only
|
||||||
|
* exist at the application level are filtered out.
|
||||||
|
*/
|
||||||
|
class GhidraPluginsConfiguration extends PluginsConfiguration {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean accepts(Class<? extends Plugin> c) {
|
||||||
|
return !(ApplicationLevelOnlyPlugin.class.isAssignableFrom(c));
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,11 +28,11 @@ import docking.action.MenuData;
|
||||||
import docking.tool.ToolConstants;
|
import docking.tool.ToolConstants;
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import ghidra.app.util.FileOpenDropHandler;
|
import ghidra.app.util.FileOpenDropHandler;
|
||||||
import ghidra.framework.main.ApplicationLevelOnlyPlugin;
|
|
||||||
import ghidra.framework.model.Project;
|
import ghidra.framework.model.Project;
|
||||||
import ghidra.framework.model.ToolTemplate;
|
import ghidra.framework.model.ToolTemplate;
|
||||||
import ghidra.framework.options.PreferenceState;
|
import ghidra.framework.options.PreferenceState;
|
||||||
import ghidra.framework.plugintool.*;
|
import ghidra.framework.plugintool.PluginConfigurationModel;
|
||||||
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.framework.plugintool.dialog.*;
|
import ghidra.framework.plugintool.dialog.*;
|
||||||
import ghidra.framework.plugintool.util.*;
|
import ghidra.framework.plugintool.util.*;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
|
@ -55,9 +55,6 @@ public class GhidraTool extends PluginTool {
|
||||||
public static boolean autoSave = true;
|
public static boolean autoSave = true;
|
||||||
|
|
||||||
private FileOpenDropHandler fileOpenDropHandler;
|
private FileOpenDropHandler fileOpenDropHandler;
|
||||||
|
|
||||||
private PluginClassManager pluginClassManager;
|
|
||||||
|
|
||||||
private DockingAction configureToolAction;
|
private DockingAction configureToolAction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,12 +96,8 @@ public class GhidraTool extends PluginTool {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PluginClassManager getPluginClassManager() {
|
protected PluginsConfiguration createPluginsConfigurations() {
|
||||||
if (pluginClassManager == null) {
|
return new GhidraPluginsConfiguration();
|
||||||
pluginClassManager =
|
|
||||||
new PluginClassManager(Plugin.class, ApplicationLevelOnlyPlugin.class);
|
|
||||||
}
|
|
||||||
return pluginClassManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -254,8 +247,7 @@ public class GhidraTool extends PluginTool {
|
||||||
int option = OptionDialog.showYesNoDialog(getActiveWindow(), "New Plugins Found!",
|
int option = OptionDialog.showYesNoDialog(getActiveWindow(), "New Plugins Found!",
|
||||||
"New extension plugins detected. Would you like to configure them?");
|
"New extension plugins detected. Would you like to configure them?");
|
||||||
if (option == OptionDialog.YES_OPTION) {
|
if (option == OptionDialog.YES_OPTION) {
|
||||||
List<PluginDescription> pluginDescriptions =
|
List<PluginDescription> pluginDescriptions = getPluginDescriptions(this, newPlugins);
|
||||||
PluginUtils.getPluginDescriptions(this, newPlugins);
|
|
||||||
PluginInstallerDialog pluginInstaller = new PluginInstallerDialog("New Plugins Found!",
|
PluginInstallerDialog pluginInstaller = new PluginInstallerDialog("New Plugins Found!",
|
||||||
this, new PluginConfigurationModel(this), pluginDescriptions);
|
this, new PluginConfigurationModel(this), pluginDescriptions);
|
||||||
showDialog(pluginInstaller);
|
showDialog(pluginInstaller);
|
||||||
|
@ -265,6 +257,43 @@ public class GhidraTool extends PluginTool {
|
||||||
addInstalledExtensions(newExtensions);
|
addInstalledExtensions(newExtensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds all {@link PluginDescription} objects that match a given set of plugin classes. This
|
||||||
|
* effectively tells the caller which of the given plugins have been loaded by the class loader.
|
||||||
|
* <p>
|
||||||
|
* Note that this method does not take path/package information into account when finding
|
||||||
|
* plugins; in the example above, if there is more than one plugin with the name "FooPlugin",
|
||||||
|
* only one will be found (the one found is not guaranteed to be the first).
|
||||||
|
*
|
||||||
|
* @param tool the current tool
|
||||||
|
* @param plugins the list of plugin classes to search for
|
||||||
|
* @return list of plugin descriptions
|
||||||
|
*/
|
||||||
|
private List<PluginDescription> getPluginDescriptions(PluginTool tool, List<Class<?>> plugins) {
|
||||||
|
|
||||||
|
// First define the list of plugin descriptions to return
|
||||||
|
List<PluginDescription> retPlugins = new ArrayList<>();
|
||||||
|
|
||||||
|
// Get all plugins that have been loaded
|
||||||
|
PluginsConfiguration pluginClassManager = getPluginsConfiguration();
|
||||||
|
List<PluginDescription> allPluginDescriptions =
|
||||||
|
pluginClassManager.getManagedPluginDescriptions();
|
||||||
|
|
||||||
|
// see if an entry exists in the list of all loaded plugins
|
||||||
|
for (Class<?> plugin : plugins) {
|
||||||
|
String pluginName = plugin.getSimpleName();
|
||||||
|
|
||||||
|
Optional<PluginDescription> desc = allPluginDescriptions.stream()
|
||||||
|
.filter(d -> (pluginName.equals(d.getName())))
|
||||||
|
.findAny();
|
||||||
|
if (desc.isPresent()) {
|
||||||
|
retPlugins.add(desc.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retPlugins;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes any extensions in the tool preferences that are no longer installed.
|
* Removes any extensions in the tool preferences that are no longer installed.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.framework.plugintool;
|
package ghidra.framework.plugintool;
|
||||||
|
|
||||||
import ghidra.framework.plugintool.util.PluginClassManager;
|
import ghidra.framework.plugintool.util.PluginsConfiguration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dummy version of {@link PluginTool} that tests can use when they need an instance of
|
* A dummy version of {@link PluginTool} that tests can use when they need an instance of
|
||||||
|
@ -29,7 +29,7 @@ public class DummyPluginTool extends PluginTool {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PluginClassManager getPluginClassManager() {
|
protected PluginsConfiguration createPluginsConfigurations() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -425,7 +425,7 @@ public class DummyTool extends PluginTool {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PluginClassManager getPluginClassManager() {
|
protected PluginsConfiguration createPluginsConfigurations() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue