start connecting OSGi to bundlestatusmanager

- minimize access to BundleHost instance (JavaScriptProvider is still bad)
- BundlePath
  - restrict construction to osgi package
  - remove "editable" attribute and fix incorrect reference
  - remove references in GhidraScriptUtil
    - BundlePath attribute choice came down only to system or user
    - user filtering on "enabled" were redundant
- move compilation from JavaScriptProvider to BundheHost
This commit is contained in:
Jason P. Leasure 2020-03-30 13:02:27 -04:00
parent 36f4a219d9
commit f39d55cca1
14 changed files with 352 additions and 282 deletions

View file

@ -39,9 +39,9 @@ import docking.widgets.tree.GTree;
import docking.widgets.tree.GTreeNode; import docking.widgets.tree.GTreeNode;
import docking.widgets.tree.support.BreadthFirstIterator; import docking.widgets.tree.support.BreadthFirstIterator;
import generic.jar.ResourceFile; import generic.jar.ResourceFile;
import generic.util.Path;
import ghidra.app.plugin.core.script.osgi.*; import ghidra.app.plugin.core.script.osgi.*;
import ghidra.app.script.*; import ghidra.app.script.*;
import ghidra.app.script.osgi.BundleHost;
import ghidra.app.services.ConsoleService; import ghidra.app.services.ConsoleService;
import ghidra.framework.options.SaveState; import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.framework.plugintool.ComponentProviderAdapter;
@ -97,9 +97,10 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
} }
}; };
GhidraScriptComponentProvider(GhidraScriptMgrPlugin plugin) { GhidraScriptComponentProvider(GhidraScriptMgrPlugin plugin, BundleHost bundleHost) {
super(plugin.getTool(), "Script Manager", plugin.getName()); super(plugin.getTool(), "Script Manager", plugin.getName());
this.plugin = plugin; this.plugin = plugin;
this.bundleHost=bundleHost;
setHelpLocation(new HelpLocation(plugin.getName(), plugin.getName())); setHelpLocation(new HelpLocation(plugin.getName(), plugin.getName()));
setIcon(ResourceManager.loadImage("images/play.png")); setIcon(ResourceManager.loadImage("images/play.png"));
@ -161,8 +162,7 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
void renameScript() { void renameScript() {
ResourceFile script = getSelectedScript(); ResourceFile script = getSelectedScript();
ResourceFile directory = script.getParentFile(); ResourceFile directory = script.getParentFile();
Path path = GhidraScriptUtil.getScriptPath(directory); if (!bundleStatusProvider.getModel().isWriteable(directory)) {
if (path == null || path.isReadOnly()) {
Msg.showWarn(getClass(), getComponent(), getName(), Msg.showWarn(getClass(), getComponent(), getName(),
"Unable to rename scripts in '" + directory + "'."); "Unable to rename scripts in '" + directory + "'.");
return; return;
@ -297,8 +297,7 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
} }
ResourceFile directory = script.getParentFile(); ResourceFile directory = script.getParentFile();
Path path = GhidraScriptUtil.getScriptPath(directory); if (!bundleStatusProvider.getModel().isWriteable(directory)) {
if (path == null || path.isReadOnly()) {
Msg.showWarn(getClass(), getComponent(), getName(), Msg.showWarn(getClass(), getComponent(), getName(),
"Unable to delete scripts in '" + directory + "'."); "Unable to delete scripts in '" + directory + "'.");
return; return;
@ -339,9 +338,9 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
} }
} }
public List<BundlePath> getScriptDirectories() { public List<ResourceFile> getScriptDirectories() {
return bundleStatusProvider.getModel().getPaths().stream().filter( return bundleStatusProvider.getModel().getPaths().stream().filter(
BundlePath::isDirectory).collect(Collectors.toList()); ResourceFile::isDirectory).collect(Collectors.toList());
} }
public void enableScriptDirectory(ResourceFile scriptDir) { public void enableScriptDirectory(ResourceFile scriptDir) {
@ -396,9 +395,9 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
} }
void runScript(String scriptName, TaskListener listener) { void runScript(String scriptName, TaskListener listener) {
List<BundlePath> dirPaths = bundleStatusProvider.getModel().getPaths(); List<ResourceFile> dirPaths = bundleStatusProvider.getModel().getPaths();
for (Path dir : dirPaths) { for (ResourceFile dir : dirPaths) {
ResourceFile scriptSource = new ResourceFile(dir.getPath(), scriptName); ResourceFile scriptSource = new ResourceFile(dir, scriptName);
if (scriptSource.exists()) { if (scriptSource.exists()) {
runScript(scriptSource, listener); runScript(scriptSource, listener);
return; return;
@ -536,11 +535,11 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
private void updateAvailableScriptFilesForAllPaths() { private void updateAvailableScriptFilesForAllPaths() {
List<ResourceFile> scriptsToRemove = tableModel.getScripts(); List<ResourceFile> scriptsToRemove = tableModel.getScripts();
List<ResourceFile> scriptAccumulator = new ArrayList<>(); List<ResourceFile> scriptAccumulator = new ArrayList<>();
List<BundlePath> bundlePaths = bundleStatusProvider.getModel().getPaths(); List<ResourceFile> bundlePaths = bundleStatusProvider.getModel().getPaths();
for (BundlePath bundlePath : bundlePaths) { for (ResourceFile bundlePath : bundlePaths) {
if (bundlePath.isDirectory()) { if (bundlePath.isDirectory()) {
updateAvailableScriptFilesForDirectory(scriptsToRemove, scriptAccumulator, updateAvailableScriptFilesForDirectory(scriptsToRemove, scriptAccumulator,
bundlePath.getPath()); bundlePath);
} }
} }
@ -731,8 +730,33 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
return true; return true;
} }
private void build() { final private BundleHost bundleHost;
void startActivateDeactiveTask(BundlePath path, boolean activate) {
path.setBusy(true);
bundleStatusProvider.notifyTableChanged();
new TaskLauncher(new Task((activate ? "Activating" : "Deactivating ") + " bundle...") {
@Override
public void run(TaskMonitor monitor) throws CancelledException {
try {
bundleHost.setActive(path, activate);
path.setActive(activate);
}
catch (Exception e) {
Msg.showError(this, GhidraScriptComponentProvider.this.getComponent(),
"activation failed", e);
}
finally {
path.setBusy(false);
bundleStatusProvider.notifyTableChanged();
}
}
}, null, 1000);
}
private void build() {
bundleStatusProvider = new BundleStatusProvider(plugin.getTool(), plugin.getName()); bundleStatusProvider = new BundleStatusProvider(plugin.getTool(), plugin.getName());
bundleStatusProvider.addListener(new BundlePathManagerListener() { bundleStatusProvider.addListener(new BundlePathManagerListener() {
@ -744,8 +768,10 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
@Override @Override
public void bundleEnablementChanged(BundlePath path, boolean enabled) { public void bundleEnablementChanged(BundlePath path, boolean enabled) {
System.err.printf("XXXX %s is now %s\n", path.toString(), if (path.isActive()) {
enabled ? "enabled" : "disabled"); startActivateDeactiveTask(path, false);
}
if (path.isDirectory()) { if (path.isDirectory()) {
performRefresh(); performRefresh();
} }
@ -753,8 +779,7 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
@Override @Override
public void bundleActivationChanged(BundlePath path, boolean newValue) { public void bundleActivationChanged(BundlePath path, boolean newValue) {
System.err.printf("XXXX %s is now %s\n", path.toString(), startActivateDeactiveTask(path, newValue);
newValue ? "active" : "inactive");
} }
}); });
@ -1026,7 +1051,7 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
bundleStatusProvider.restoreState(saveState); bundleStatusProvider.restoreState(saveState);
// pull in the just-loaded paths // pull in the just-loaded paths
List<BundlePath> paths = bundleStatusProvider.getModel().getPaths(); List<ResourceFile> paths = bundleStatusProvider.getModel().getPaths();
GhidraScriptUtil.setScriptBundlePaths(paths); GhidraScriptUtil.setScriptBundlePaths(paths);
actionManager.restoreUserDefinedKeybindings(saveState); actionManager.restoreUserDefinedKeybindings(saveState);
actionManager.restoreScriptsThatAreInTool(saveState); actionManager.restoreScriptsThatAreInTool(saveState);
@ -1162,4 +1187,10 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
} }
} }
public List<ResourceFile> getWritableScriptDirectories() {
BundleStatusModel m = bundleStatusProvider.getModel();
return m.getPaths().stream().filter(ResourceFile::isDirectory).filter(
m::isWriteable).collect(Collectors.toList());
}
} }

View file

@ -26,6 +26,7 @@ import ghidra.app.plugin.ProgramPlugin;
import ghidra.app.plugin.core.eclipse.EclipseConnection; import ghidra.app.plugin.core.eclipse.EclipseConnection;
import ghidra.app.plugin.core.eclipse.EclipseIntegrationOptionsPlugin; import ghidra.app.plugin.core.eclipse.EclipseIntegrationOptionsPlugin;
import ghidra.app.script.GhidraState; import ghidra.app.script.GhidraState;
import ghidra.app.script.osgi.BundleHost;
import ghidra.app.services.*; import ghidra.app.services.*;
import ghidra.framework.options.SaveState; import ghidra.framework.options.SaveState;
import ghidra.framework.options.ToolOptions; import ghidra.framework.options.ToolOptions;
@ -48,12 +49,15 @@ import ghidra.util.task.TaskListener;
//@formatter:on //@formatter:on
public class GhidraScriptMgrPlugin extends ProgramPlugin implements GhidraScriptService { public class GhidraScriptMgrPlugin extends ProgramPlugin implements GhidraScriptService {
private GhidraScriptComponentProvider provider; final private GhidraScriptComponentProvider provider;
final private BundleHost bundleHost;
public GhidraScriptMgrPlugin(PluginTool tool) { public GhidraScriptMgrPlugin(PluginTool tool) {
super(tool, true, true, true); super(tool, true, true, true);
provider = new GhidraScriptComponentProvider(this); bundleHost = BundleHost.getInstance();
provider = new GhidraScriptComponentProvider(this, bundleHost);
} }
@Override @Override

View file

@ -19,7 +19,8 @@ import java.awt.BorderLayout;
import java.awt.Component; import java.awt.Component;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.ArrayList;
import java.util.List;
import javax.swing.*; import javax.swing.*;
import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionEvent;
@ -31,7 +32,6 @@ import docking.widgets.MultiLineLabel;
import docking.widgets.label.GLabel; import docking.widgets.label.GLabel;
import docking.widgets.list.ListPanel; import docking.widgets.list.ListPanel;
import generic.jar.ResourceFile; import generic.jar.ResourceFile;
import generic.util.Path;
import ghidra.app.script.*; import ghidra.app.script.*;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
@ -49,7 +49,7 @@ public class SaveDialog extends DialogComponentProvider implements ListSelection
public SaveDialog(Component parent, String title, public SaveDialog(Component parent, String title,
GhidraScriptComponentProvider componentProvider, ResourceFile scriptFile, GhidraScriptComponentProvider componentProvider, ResourceFile scriptFile,
HelpLocation help) { HelpLocation help) {
this(parent, title, componentProvider, getScriptPaths(), scriptFile, help); this(parent, title, componentProvider, componentProvider.getWritableScriptDirectories(), scriptFile, help);
} }
public SaveDialog(Component parent, String title, public SaveDialog(Component parent, String title,
@ -85,21 +85,6 @@ public class SaveDialog extends DialogComponentProvider implements ListSelection
DockingWindowManager.showDialog(parent, this); DockingWindowManager.showDialog(parent, this);
} }
private static List<ResourceFile> getScriptPaths() {
List<ResourceFile> newPaths = new ArrayList<>();
List<ResourceFile> scriptPaths = GhidraScriptUtil.getScriptSourceDirectories();
for (ResourceFile directory : scriptPaths) {
Path path = GhidraScriptUtil.getScriptPath(directory);
if (path != null && !path.isReadOnly()) {
newPaths.add(directory);
}
}
Collections.sort(newPaths);
return newPaths;
}
private JPanel buildNamePanel() { private JPanel buildNamePanel() {
nameField = new JTextField(20); nameField = new JTextField(20);
nameField.setText(scriptFile == null ? "" : scriptFile.getName()); nameField.setText(scriptFile == null ? "" : scriptFile.getName());

View file

@ -21,7 +21,10 @@ import generic.jar.ResourceFile;
import generic.util.Path; import generic.util.Path;
public class BundlePath extends Path { public class BundlePath extends Path {
final Type type;
boolean active = false; boolean active = false;
boolean busy = false;
public static enum Type { public static enum Type {
BndScript, Jar, SourceDir, INVALID BndScript, Jar, SourceDir, INVALID
@ -55,47 +58,43 @@ public class BundlePath extends Path {
return Type.INVALID; return Type.INVALID;
} }
final Type type;
public BundlePath(File path) {
super(path);
type = getType(getPath());
}
public Type getType() { public Type getType() {
return type; return type;
} }
public BundlePath(ResourceFile rf) { BundlePath(String path, boolean enabled, boolean readonly) {
super(rf); super(path, enabled, false /*editable */, readonly);
type = getType(getPath()); type = getType(getPath());
} }
public BundlePath(String absolutePath) { BundlePath(ResourceFile path, boolean enabled, boolean readonly) {
super(absolutePath); super(path, enabled, false /* editable */, readonly);
type = getType(getPath()); type = getType(getPath());
} }
public BundlePath(String a, boolean b, boolean c, boolean d) {
super(a, b, c, d);
type = getType(getPath());
}
public BundlePath(ResourceFile a, boolean b, boolean c, boolean d) {
super(a, b, c, d);
type = getType(getPath());
}
public boolean isActive() {
return active;
}
public void setActive(Boolean b) {
active = b;
}
public boolean isDirectory() { public boolean isDirectory() {
return getPath().isDirectory(); return getPath().isDirectory();
} }
public boolean isActive() {
return active;
}
@Override
public boolean isEditable() {
return false;
}
public void setActive(boolean b) {
active = b;
}
public void setBusy(boolean b) {
busy = b;
}
public boolean getBusy() {
return busy;
}
} }

View file

@ -16,8 +16,8 @@
*/ */
package ghidra.app.plugin.core.script.osgi; package ghidra.app.plugin.core.script.osgi;
import java.util.ArrayList; import java.util.*;
import java.util.List; import java.util.stream.Collectors;
import docking.widgets.table.AbstractSortedTableModel; import docking.widgets.table.AbstractSortedTableModel;
import generic.jar.ResourceFile; import generic.jar.ResourceFile;
@ -41,20 +41,25 @@ public class BundleStatusModel extends AbstractSortedTableModel<BundlePath> {
} }
boolean editable(BundlePath path) { boolean editable(BundlePath path) {
return true; return false;
} }
Object getValue(BundlePath path) { Object getValue(BundlePath path) {
return path; return null;
} }
void setValue(BundlePath path, Object aValue) { void setValue(BundlePath path, Object aValue) {
// do nothing throw new RuntimeException(name + " is not editable!");
} }
} }
Column enabledColumn = new Column("Enabled", Boolean.class) { Column enabledColumn = new Column("Enabled", Boolean.class) {
@Override
boolean editable(BundlePath path) {
return path.exists();
}
@Override @Override
Object getValue(BundlePath path) { Object getValue(BundlePath path) {
return path.isEnabled(); return path.isEnabled();
@ -67,6 +72,11 @@ public class BundleStatusModel extends AbstractSortedTableModel<BundlePath> {
} }
}; };
Column activeColumn = new Column("Active", Boolean.class) { Column activeColumn = new Column("Active", Boolean.class) {
@Override
boolean editable(BundlePath path) {
return path.exists(); // XXX maybe only if it's already enabled
}
@Override @Override
Object getValue(BundlePath path) { Object getValue(BundlePath path) {
return path.isActive(); return path.isActive();
@ -93,15 +103,12 @@ public class BundleStatusModel extends AbstractSortedTableModel<BundlePath> {
Column pathColumn = new Column("Path", BundlePath.class) { Column pathColumn = new Column("Path", BundlePath.class) {
@Override @Override
boolean editable(BundlePath path) { boolean editable(BundlePath path) {
return true; return false;
} }
@Override @Override
void setValue(BundlePath path, Object aValue) { Object getValue(BundlePath path) {
if (path.isEditable()) { return path;
BundlePath newpath = (BundlePath) aValue;
path.setPath(newpath.getPath());
}
} }
}; };
Column badColumn = new Column("INVALID", Object.class); Column badColumn = new Column("INVALID", Object.class);
@ -118,26 +125,21 @@ public class BundleStatusModel extends AbstractSortedTableModel<BundlePath> {
} }
private BundleStatusProvider provider; private BundleStatusProvider provider;
private List<BundlePath> paths = new ArrayList<>(); private List<BundlePath> paths;
BundleStatusModel(BundleStatusProvider provider) { BundleStatusModel(BundleStatusProvider provider) {
super(); super();
this.provider = provider; this.provider = provider;
this.paths.addAll(dedupPaths(GhidraScriptUtil.getDefaultScriptBundles()));
// add unmodifiable paths
this.paths = GhidraScriptUtil.getSystemScriptPaths().stream().distinct().map(
f -> new BundlePath(f, true, true)).collect(Collectors.toList());
// add user path
this.paths.add(0, new BundlePath(GhidraScriptUtil.getUserScriptDirectory(), true, false));
fireTableDataChanged(); fireTableDataChanged();
} }
private List<BundlePath> dedupPaths(List<BundlePath> newPaths) {
List<BundlePath> dedupedPaths = new ArrayList<>();
for (BundlePath path : newPaths) {
if (!dedupedPaths.contains(path)) {
dedupedPaths.add(path);
}
}
return dedupedPaths;
}
void clear() { void clear() {
paths.clear(); paths.clear();
} }
@ -146,21 +148,16 @@ public class BundleStatusModel extends AbstractSortedTableModel<BundlePath> {
return new ArrayList<BundlePath>(paths); return new ArrayList<BundlePath>(paths);
} }
public List<BundlePath> getPaths() { public List<ResourceFile> getPaths() {
List<BundlePath> list = new ArrayList<>(); List<ResourceFile> list = new ArrayList<>();
for (BundlePath path : paths) { for (BundlePath path : paths) {
if (path.isEnabled()) { if (path.isEnabled()) {
list.add(path); list.add(path.getPath());
} }
} }
return list; return list;
} }
public void setPaths(List<BundlePath> paths) {
this.paths = new ArrayList<>(paths);
fireTableDataChanged();
}
void addPath(BundlePath path) { void addPath(BundlePath path) {
if (paths.contains(path)) { if (paths.contains(path)) {
return; return;
@ -176,7 +173,7 @@ public class BundleStatusModel extends AbstractSortedTableModel<BundlePath> {
list.add(paths.get(selectedRow)); list.add(paths.get(selectedRow));
} }
for (BundlePath path : list) { for (BundlePath path : list) {
if (path.isEditable()) { if (!path.isReadOnly()) {
paths.remove(path); paths.remove(path);
} }
else { else {
@ -259,11 +256,48 @@ public class BundleStatusModel extends AbstractSortedTableModel<BundlePath> {
return false; return false;
} }
} }
BundlePath p = new BundlePath(dir); BundlePath p = new BundlePath(dir, true, false);
p.setEnabled(true);
addPath(p); addPath(p);
Preferences.setProperty(BundleStatusProvider.preferenceForLastSelectedBundle, dir.getAbsolutePath()); Preferences.setProperty(BundleStatusProvider.preferenceForLastSelectedBundle,
dir.getAbsolutePath());
provider.fireBundlesChanged(); provider.fireBundlesChanged();
return true; return true;
} }
/**
* Test whether the given <code>bundle</code> is managed and not marked readonly
* @param bundle the path to test
* @return true if the bundle is managed and not marked readonly
*/
public boolean isWriteable(ResourceFile bundle) {
Optional<BundlePath> o = paths.stream().filter(
bp -> bp.isDirectory() && bp.getPath().equals(bundle)).findFirst();
return o.isPresent() && !o.get().isReadOnly();
}
/**
* This is for testing only!
*
* each path is marked editable and non-readonly
*
* @param testingPaths the paths to use
*/
public void setPathsForTesting(List<String> testingPaths) {
this.paths = testingPaths.stream().map(f -> new BundlePath(f, true, false)).collect(
Collectors.toList());
fireTableDataChanged();
}
/**
* This is for testing only!
*
* insert path, marked editable and non-readonly
* @param index index to insert at
* @param path the path to insert
*/
public void insertPathForTesting(int index, String path) {
paths.add(0, new BundlePath(path, true, false));
fireTableRowsInserted(0, 0);
}
} }

View file

@ -22,11 +22,13 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import javax.swing.*; import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.table.TableColumn; import javax.swing.table.TableColumn;
import docking.widgets.filechooser.GhidraFileChooser; import docking.widgets.filechooser.GhidraFileChooser;
import docking.widgets.filechooser.GhidraFileChooserMode; import docking.widgets.filechooser.GhidraFileChooserMode;
import docking.widgets.table.*; import docking.widgets.table.*;
import generic.jar.ResourceFile;
import ghidra.framework.options.SaveState; import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.framework.plugintool.ComponentProviderAdapter;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
@ -51,6 +53,10 @@ public class BundleStatusProvider extends ComponentProviderAdapter {
private GhidraFileFilter filter; private GhidraFileFilter filter;
private ArrayList<BundlePathManagerListener> listeners = new ArrayList<>(); private ArrayList<BundlePathManagerListener> listeners = new ArrayList<>();
public void notifyTableChanged() {
bundlePathTable.notifyTableChanged(new TableModelEvent(bundleStatusModel));
}
void fireBundlesChanged() { void fireBundlesChanged() {
for (BundlePathManagerListener listener : listeners) { for (BundlePathManagerListener listener : listeners) {
listener.bundlesChanged(); listener.bundlesChanged();
@ -138,6 +144,9 @@ public class BundleStatusProvider extends ComponentProviderAdapter {
bundlePathTable.setSelectionForeground(Color.BLACK); bundlePathTable.setSelectionForeground(Color.BLACK);
bundlePathTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); bundlePathTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
// to allow custom cell renderers
bundlePathTable.setAutoCreateColumnsFromModel(false);
int skinnyWidth = 50; int skinnyWidth = 50;
TableColumn column = TableColumn column =
@ -152,6 +161,27 @@ public class BundleStatusProvider extends ComponentProviderAdapter {
column.setMinWidth(skinnyWidth); column.setMinWidth(skinnyWidth);
column.setMaxWidth(skinnyWidth); column.setMaxWidth(skinnyWidth);
column.setWidth(skinnyWidth); column.setWidth(skinnyWidth);
column.setCellRenderer(new GBooleanCellRenderer() {
@Override
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
BundlePath path = (BundlePath) data.getRowObject();
Component x = super.getTableCellRendererComponent(data);
if (path.getBusy()) {
cb.setVisible(false);
cb.setEnabled(false);
setHorizontalAlignment(SwingConstants.CENTER);
setText("...");
}
else {
cb.setVisible(true);
cb.setEnabled(true);
setText("");
}
return x;
}
});
column = bundlePathTable.getColumnModel().getColumn(bundleStatusModel.typeColumn.index); column = bundlePathTable.getColumnModel().getColumn(bundleStatusModel.typeColumn.index);
@ -163,13 +193,13 @@ public class BundleStatusProvider extends ComponentProviderAdapter {
column.setCellRenderer(new GTableCellRenderer() { column.setCellRenderer(new GTableCellRenderer() {
@Override @Override
public Component getTableCellRendererComponent(GTableCellRenderingData data) { public Component getTableCellRendererComponent(GTableCellRenderingData data) {
JLabel renderer = (JLabel) super.getTableCellRendererComponent(data); JLabel c = (JLabel) super.getTableCellRendererComponent(data);
BundlePath path = (BundlePath) data.getValue(); BundlePath path = (BundlePath) data.getValue();
if (!path.exists()) { if (!path.exists()) {
renderer.setForeground(Color.RED); c.setForeground(Color.RED);
} }
return renderer; return c;
} }
}); });
@ -262,7 +292,7 @@ public class BundleStatusProvider extends ComponentProviderAdapter {
Preferences.setProperty(preferenceForLastSelectedBundle, Preferences.setProperty(preferenceForLastSelectedBundle,
files.get(0).getAbsolutePath()); files.get(0).getAbsolutePath());
for (File element : files) { for (File element : files) {
BundlePath p = new BundlePath(element); BundlePath p = new BundlePath(new ResourceFile(element), true, false);
bundleStatusModel.addPath(p); bundleStatusModel.addPath(p);
} }
fireBundlesChanged(); fireBundlesChanged();
@ -283,22 +313,19 @@ public class BundleStatusProvider extends ComponentProviderAdapter {
String[] pathArr = new String[paths.size()]; String[] pathArr = new String[paths.size()];
boolean[] enableArr = new boolean[paths.size()]; boolean[] enableArr = new boolean[paths.size()];
boolean[] editArr = new boolean[paths.size()];
boolean[] readArr = new boolean[paths.size()]; boolean[] readArr = new boolean[paths.size()];
int index = 0; int index = 0;
for (BundlePath path : paths) { for (BundlePath path : paths) {
pathArr[index] = path.getPathAsString(); pathArr[index] = path.getPathAsString();
enableArr[index] = path.isEnabled(); enableArr[index] = path.isEnabled();
editArr[index] = path.isEditable();
readArr[index] = path.isReadOnly(); readArr[index] = path.isReadOnly();
++index; ++index;
} }
ss.putStrings("BundleManagerPanel_PATH", pathArr); ss.putStrings("BundleStatus_PATH", pathArr);
ss.putBooleans("BundleManagerPanel_ENABLE", enableArr); ss.putBooleans("BundleStatus_ENABLE", enableArr);
ss.putBooleans("BundleManagerPanel_EDIT", editArr); ss.putBooleans("BundleStatus_READ", readArr);
ss.putBooleans("BundleManagerPanel_READ", readArr);
} }
/** /**
@ -306,22 +333,21 @@ public class BundleStatusProvider extends ComponentProviderAdapter {
* @param ss the SaveState object * @param ss the SaveState object
*/ */
public void restoreState(SaveState ss) { public void restoreState(SaveState ss) {
String[] pathArr = ss.getStrings("BundleManagerPanel_PATH", new String[0]); String[] pathArr = ss.getStrings("BundleStatus_PATH", new String[0]);
if (pathArr.length == 0) { if (pathArr.length == 0) {
return; return;
} }
boolean[] enableArr = boolean[] enableArr =
ss.getBooleans("BundleManagerPanel_ENABLE", new boolean[pathArr.length]); ss.getBooleans("BundleStatus_ENABLE", new boolean[pathArr.length]);
boolean[] editArr = ss.getBooleans("BundleManagerPanel_EDIT", new boolean[pathArr.length]); boolean[] readArr = ss.getBooleans("BundleStatus_READ", new boolean[pathArr.length]);
boolean[] readArr = ss.getBooleans("BundleManagerPanel_READ", new boolean[pathArr.length]);
List<BundlePath> oldPaths = bundleStatusModel.getAllPaths(); List<BundlePath> oldPaths = bundleStatusModel.getAllPaths();
bundleStatusModel.clear(); bundleStatusModel.clear();
for (int i = 0; i < pathArr.length; i++) { for (int i = 0; i < pathArr.length; i++) {
BundlePath path = new BundlePath(pathArr[i], enableArr[i], editArr[i], readArr[i]); BundlePath path = new BundlePath(pathArr[i], enableArr[i], readArr[i]);
BundlePath oldPath = getPath(path.getPathAsString(), oldPaths); BundlePath oldPath = getPath(path.getPathAsString(), oldPaths);
if (oldPath != null) { if (oldPath != null) {
if (!oldPath.isEditable()) { if (!oldPath.isEditable()) {
@ -361,7 +387,4 @@ public class BundleStatusProvider extends ComponentProviderAdapter {
bundlePathTable.dispose(); bundlePathTable.dispose();
} }
void selectRow(int rowIndex) {
bundlePathTable.selectRow(rowIndex);
}
} }

View file

@ -24,7 +24,6 @@ import java.util.stream.Collectors;
import org.apache.commons.collections4.map.LazyMap; import org.apache.commons.collections4.map.LazyMap;
import generic.jar.ResourceFile; import generic.jar.ResourceFile;
import ghidra.app.plugin.core.script.osgi.BundlePath;
import ghidra.framework.Application; import ghidra.framework.Application;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.Msg; import ghidra.util.Msg;
@ -48,7 +47,7 @@ public class GhidraScriptUtil {
*/ */
public static String USER_SCRIPTS_DIR = buildUserScriptsDirectory(); public static String USER_SCRIPTS_DIR = buildUserScriptsDirectory();
private static List<BundlePath> scriptBundlePaths = new ArrayList<>(); private static List<ResourceFile> scriptBundlePaths = new ArrayList<>();
private static Map<ResourceFile, ScriptInfo> scriptFileToInfoMap = new HashMap<>(); private static Map<ResourceFile, ScriptInfo> scriptFileToInfoMap = new HashMap<>();
@ -56,7 +55,8 @@ public class GhidraScriptUtil {
LazyMap.lazyMap(new HashMap<String, List<ResourceFile>>(), () -> new ArrayList<>()); LazyMap.lazyMap(new HashMap<String, List<ResourceFile>>(), () -> new ArrayList<>());
static { static {
scriptBundlePaths = getDefaultScriptBundles(); scriptBundlePaths = getSystemScriptPaths();
scriptBundlePaths.add(0, getUserScriptDirectory());
} }
/** /**
@ -81,25 +81,22 @@ public class GhidraScriptUtil {
* Returns a list of the default script directories. * Returns a list of the default script directories.
* @return a list of the default script directories * @return a list of the default script directories
*/ */
public static List<BundlePath> getDefaultScriptBundles() { public static List<ResourceFile> getSystemScriptPaths() {
List<ResourceFile> pathsList = new ArrayList<>();
List<BundlePath> pathsList = new ArrayList<>();
addScriptPaths(pathsList, SCRIPTS_SUBDIR_NAME); addScriptPaths(pathsList, SCRIPTS_SUBDIR_NAME);
addScriptPaths(pathsList, DEV_SCRIPTS_SUBDIR_NAME); addScriptPaths(pathsList, DEV_SCRIPTS_SUBDIR_NAME);
Collections.sort(pathsList); Collections.sort(pathsList);
// this one should always be first
pathsList.add(0, new BundlePath(new ResourceFile(USER_SCRIPTS_DIR), true, false, false));
return pathsList; return pathsList;
} }
private static void addScriptPaths(List<BundlePath> pathsList, String directoryName) { public static ResourceFile getUserScriptDirectory() {
Iterable<ResourceFile> files = Application.findModuleSubDirectories(directoryName); return new ResourceFile(USER_SCRIPTS_DIR);
for (ResourceFile file : files) {
pathsList.add(new BundlePath(file, true, false, true));
} }
private static void addScriptPaths(List<ResourceFile> pathsList, String directoryName) {
pathsList.addAll(Application.findModuleSubDirectories(directoryName));
} }
/** /**
@ -144,39 +141,18 @@ public class GhidraScriptUtil {
* @return a list of the current script directories * @return a list of the current script directories
*/ */
public static List<ResourceFile> getScriptSourceDirectories() { public static List<ResourceFile> getScriptSourceDirectories() {
ArrayList<ResourceFile> dirs = new ArrayList<>(); return scriptBundlePaths.stream().filter(ResourceFile::isDirectory).collect(
for (BundlePath path : scriptBundlePaths) { Collectors.toList());
if (path.isDirectory()) {
dirs.add(path.getPath());
}
}
return dirs;
} }
/** /**
* Sets the script bundle paths * Sets the script bundle paths
* @param newPaths the new script bundle paths * @param newPaths the new script bundle paths
*/ */
public static void setScriptBundlePaths(List<BundlePath> newPaths) { public static void setScriptBundlePaths(List<ResourceFile> newPaths) {
scriptBundlePaths = new ArrayList<>(newPaths); scriptBundlePaths = new ArrayList<>(newPaths);
} }
/**
* Returns the PATH for the specified directory.
* @param directory the directory
* @return the path for the specified directory
*/
public static BundlePath getScriptPath(ResourceFile directory) {
if (directory.isDirectory()) {
for (BundlePath path : scriptBundlePaths) {
if (path.getPath().equals(directory)) {
return path;
}
}
}
return null;
}
public static Path getOsgiDir() { public static Path getOsgiDir() {
Path usersettings = Application.getUserSettingsDirectory().toPath(); Path usersettings = Application.getUserSettingsDirectory().toPath();
return usersettings.resolve("osgi"); return usersettings.resolve("osgi");
@ -218,7 +194,7 @@ public class GhidraScriptUtil {
} }
Set<ResourceFile> dirs = new HashSet<>(); Set<ResourceFile> dirs = new HashSet<>();
for (BundlePath path : scriptBundlePaths) { for (ResourceFile scriptDir : scriptBundlePaths) {
// //
// Assumed structure of script dir path: // Assumed structure of script dir path:
// /some/path/Ghidra/Features/Module/ghidra_scripts // /some/path/Ghidra/Features/Module/ghidra_scripts
@ -226,7 +202,6 @@ public class GhidraScriptUtil {
// Desired path: // Desired path:
// /some/path/Ghidra/Features/Module/bin/scripts // /some/path/Ghidra/Features/Module/bin/scripts
ResourceFile scriptDir = path.getPath();
ResourceFile moduleDir = scriptDir.getParentFile(); ResourceFile moduleDir = scriptDir.getParentFile();
dirs.add(new ResourceFile(moduleDir, BIN_DIR_NAME + File.separator + "scripts")); dirs.add(new ResourceFile(moduleDir, BIN_DIR_NAME + File.separator + "scripts"));
} }
@ -381,14 +356,14 @@ public class GhidraScriptUtil {
* @throws IOException if an i/o error occurs * @throws IOException if an i/o error occurs
*/ */
public static ResourceFile createNewScript(GhidraScriptProvider provider, public static ResourceFile createNewScript(GhidraScriptProvider provider,
ResourceFile parentDirectory, List<BundlePath> scriptDirectories) throws IOException { ResourceFile parentDirectory, List<ResourceFile> scriptDirectories) throws IOException {
String baseName = GhidraScriptConstants.DEFAULT_SCRIPT_NAME; String baseName = GhidraScriptConstants.DEFAULT_SCRIPT_NAME;
String extension = provider.getExtension(); String extension = provider.getExtension();
return createNewScript(baseName, extension, parentDirectory, scriptDirectories); return createNewScript(baseName, extension, parentDirectory, scriptDirectories);
} }
private static ResourceFile createNewScript(String scriptName, String extension, private static ResourceFile createNewScript(String scriptName, String extension,
ResourceFile parentDirctory, List<BundlePath> scriptDirectories) throws IOException { ResourceFile parentDirctory, List<ResourceFile> scriptDirectories) throws IOException {
String baseName = scriptName; String baseName = scriptName;
String className = baseName + extension; String className = baseName + extension;
@ -409,13 +384,12 @@ public class GhidraScriptUtil {
} }
/** Returns true if the given filename exists in any of the given directories */ /** Returns true if the given filename exists in any of the given directories */
private static ResourceFile findScriptFileInPaths(List<BundlePath> scriptDirectories, private static ResourceFile findScriptFileInPaths(List<ResourceFile> scriptDirectories,
String filename) { String filename) {
String validatedName = fixupName(filename); String validatedName = fixupName(filename);
for (BundlePath path : scriptDirectories) { for (ResourceFile resourceFile : scriptDirectories) {
ResourceFile resourceFile = path.getPath();
if (resourceFile.isDirectory()) { if (resourceFile.isDirectory()) {
ResourceFile file = new ResourceFile(resourceFile, validatedName); ResourceFile file = new ResourceFile(resourceFile, validatedName);
if (file.exists()) { if (file.exists()) {
@ -477,8 +451,8 @@ public class GhidraScriptUtil {
public static List<ResourceFile> getAllScripts() { public static List<ResourceFile> getAllScripts() {
List<ResourceFile> scriptList = new ArrayList<>(); List<ResourceFile> scriptList = new ArrayList<>();
for (BundlePath dirPath : scriptBundlePaths) { for (ResourceFile dirPath : scriptBundlePaths) {
updateAvailableScriptFilesForDirectory(scriptList, dirPath.getPath()); updateAvailableScriptFilesForDirectory(scriptList, dirPath);
} }
return scriptList; return scriptList;
} }

View file

@ -26,7 +26,7 @@ import ghidra.app.script.osgi.*;
import ghidra.util.Msg; import ghidra.util.Msg;
public class JavaScriptProvider extends GhidraScriptProvider { public class JavaScriptProvider extends GhidraScriptProvider {
public SourceBundleInfo getBundleInfoForSource(ResourceFile sourceFile) { static public SourceBundleInfo getBundleInfoForSource(ResourceFile sourceFile) {
ResourceFile sourceDir = getSourceDirectoryContaining(sourceFile); ResourceFile sourceDir = getSourceDirectoryContaining(sourceFile);
if (sourceDir == null) { if (sourceDir == null) {
return null; return null;
@ -87,7 +87,7 @@ public class JavaScriptProvider extends GhidraScriptProvider {
} }
} }
public Class<?> loadClass(ResourceFile sourceFile, PrintWriter writer) static public Class<?> loadClass(ResourceFile sourceFile, PrintWriter writer)
throws IOException, OSGiException, ClassNotFoundException, InterruptedException { throws IOException, OSGiException, ClassNotFoundException, InterruptedException {
if (writer == null) { if (writer == null) {
@ -95,72 +95,7 @@ public class JavaScriptProvider extends GhidraScriptProvider {
} }
SourceBundleInfo bi = getBundleInfoForSource(sourceFile); SourceBundleInfo bi = getBundleInfoForSource(sourceFile);
Bundle b = BundleHost.getInstance().activate(bi, writer);
bi.updateFromFilesystem(writer);
// needsCompile => needsBundleActivate
boolean needsCompile = false;
boolean needsBundleActivate = false;
int failing = bi.getFailingSourcesCount();
int newSourcecount = bi.getNewSourcesCount();
long lastBundleActivation = 0; // XXX record last bundle activation in pathmanager
if (failing > 0 && (lastBundleActivation > bi.getLastCompileAttempt())) {
needsCompile = true;
}
if (newSourcecount == 0) {
if (failing > 0) {
writer.printf("%s hasn't changed, with %d file%s failing in previous build(s):\n",
bi.getSourceDir().toString(), failing, failing > 1 ? "s" : "");
writer.printf("%s\n", bi.getPreviousBuildErrors());
}
if (bi.newManifestFile()) {
needsCompile = true;
}
}
else {
needsCompile = true;
}
needsBundleActivate |= needsCompile;
BundleHost bundle_host = BundleHost.getInstance();
if (needsBundleActivate) {
writer.printf("%s has %d new/updated %d failed in previous build(s)%s\n",
bi.getSourceDir().toString(), newSourcecount, failing,
bi.newManifestFile() ? " and the manifest is new" : "");
// if there a bundle is currently active, uninstall it
Bundle b = bi.getBundle();
if (b != null) {
bundle_host.synchronousUninstall(b);
}
// once we've committed to recompile and regenerate generated classes, delete the old stuff
if (needsCompile) {
bi.deleteOldBinaries();
BundleCompiler bc = new BundleCompiler(bundle_host);
long startTime = System.nanoTime();
bc.compileToExplodedBundle(bi, writer);
long endTime = System.nanoTime();
writer.printf("%3.2f seconds compile time.\n", (endTime - startTime) / 1e9);
}
}
// as much source as possible built, install bundle and start it if necessary
Bundle b = bi.getBundle();
if (b == null) {
b = bi.install();
needsBundleActivate = true;
}
if (needsBundleActivate) {
bundle_host.synchronousStart(b);
}
String classname = bi.classNameForScript(sourceFile); String classname = bi.classNameForScript(sourceFile);
Class<?> clazz = b.loadClass(classname); // throws ClassNotFoundException Class<?> clazz = b.loadClass(classname); // throws ClassNotFoundException
return clazz; return clazz;

View file

@ -36,6 +36,7 @@ import org.osgi.framework.wiring.*;
import org.osgi.service.log.*; import org.osgi.service.log.*;
import generic.jar.ResourceFile; import generic.jar.ResourceFile;
import ghidra.app.plugin.core.script.osgi.BundlePath;
import ghidra.app.script.GhidraScriptUtil; import ghidra.app.script.GhidraScriptUtil;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.*; import ghidra.util.task.*;
@ -532,4 +533,101 @@ public class BundleHost {
} }
} }
/**
* Change the status of the bundle referenced by <code>path</code>
*
* @param path the bundle path to activate/deactivate
* @param value the new activation value
* @throws InterruptedException
*/
public void setActive(BundlePath path, boolean value) throws InterruptedException {
if (path.isDirectory()) {
SourceBundleInfo sbi = getSourceBundleInfo(path.getPath());
}
Thread.sleep(3000);
}
/**
* synchronously perform steps necessary to activate bundle:
* <ol>
* <li>if source bundle, checkCompile</li>
* <li>b</li>
*
* </ol>
*
* @param bi the bundle info
* @param writer where to write issues
* @throws OSGiException if bundle operations fail
* @throws IOException if there are issues with the contents of the bundle
* @return the activated bundle
* @throws InterruptedException if interrupted while waiting for bundle state change
*/
public Bundle activate(SourceBundleInfo bi, PrintWriter writer)
throws OSGiException, IOException, InterruptedException {
bi.updateFromFilesystem(writer);
// needsCompile => needsBundleActivate
boolean needsCompile = false;
boolean needsBundleActivate = false;
int failing = bi.getFailingSourcesCount();
int newSourcecount = bi.getNewSourcesCount();
long lastBundleActivation = 0; // XXX record last bundle activation in bundlestatusmodel
if (failing > 0 && (lastBundleActivation > bi.getLastCompileAttempt())) {
needsCompile = true;
}
if (newSourcecount == 0) {
if (failing > 0) {
writer.printf("%s hasn't changed, with %d file%s failing in previous build(s):\n",
bi.getSourceDir().toString(), failing, failing > 1 ? "s" : "");
writer.printf("%s\n", bi.getPreviousBuildErrors());
}
if (bi.newManifestFile()) {
needsCompile = true;
}
}
else {
needsCompile = true;
}
needsBundleActivate |= needsCompile;
if (needsBundleActivate) {
writer.printf("%s has %d new/updated %d failed in previous build(s)%s\n",
bi.getSourceDir().toString(), newSourcecount, failing,
bi.newManifestFile() ? " and the manifest is new" : "");
// if there a bundle is currently active, uninstall it
Bundle b = bi.getBundle();
if (b != null) {
synchronousUninstall(b);
}
// once we've committed to recompile and regenerate generated classes, delete the old stuff
if (needsCompile) {
bi.deleteOldBinaries();
BundleCompiler bc = new BundleCompiler(this);
long startTime = System.nanoTime();
bc.compileToExplodedBundle(bi, writer);
long endTime = System.nanoTime();
writer.printf("%3.2f seconds compile time.\n", (endTime - startTime) / 1e9);
}
}
// as much source as possible built, install bundle and start it if necessary
Bundle b = bi.getBundle();
if (b == null) {
b = bi.install();
needsBundleActivate = true;
}
if (needsBundleActivate) {
synchronousStart(b);
}
return b;
}
} }

View file

@ -22,7 +22,6 @@ import java.util.List;
import generic.jar.ResourceFile; import generic.jar.ResourceFile;
import ghidra.GhidraApplicationLayout; import ghidra.GhidraApplicationLayout;
import ghidra.GhidraLaunchable; import ghidra.GhidraLaunchable;
import ghidra.app.plugin.core.script.osgi.BundlePath;
import ghidra.app.script.*; import ghidra.app.script.*;
import ghidra.framework.Application; import ghidra.framework.Application;
import ghidra.framework.HeadlessGhidraApplicationConfiguration; import ghidra.framework.HeadlessGhidraApplicationConfiguration;
@ -31,7 +30,7 @@ import ghidra.program.database.ProgramDB;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.SystemUtilities; import ghidra.util.SystemUtilities;
import ghidra.util.task.TaskMonitorAdapter; import ghidra.util.task.TaskMonitor;
import utility.application.ApplicationLayout; import utility.application.ApplicationLayout;
/** /**
@ -76,7 +75,7 @@ public class GhidraScriptRunner implements GhidraLaunchable {
try { try {
PrintWriter writer = new PrintWriter(System.out); PrintWriter writer = new PrintWriter(System.out);
Msg.info(this, "SCRIPT: " + scriptName); Msg.info(this, "SCRIPT: " + scriptName);
script.execute(scriptState, TaskMonitorAdapter.DUMMY_MONITOR, writer); script.execute(scriptState, TaskMonitor.DUMMY, writer);
writer.flush(); writer.flush();
} }
catch (Exception exc) { catch (Exception exc) {
@ -100,8 +99,8 @@ public class GhidraScriptRunner implements GhidraLaunchable {
GhidraScriptProvider provider = GhidraScriptUtil.getProvider(scriptSourceFile); GhidraScriptProvider provider = GhidraScriptUtil.getProvider(scriptSourceFile);
if (provider == null) { if (provider == null) {
throw new IOException("Missing plugin needed to run scripts of this type. Please " throw new IOException("Missing plugin needed to run scripts of this type. Please " +
+ "ensure you have installed the necessary plugin."); "ensure you have installed the necessary plugin.");
} }
PrintWriter writer = new PrintWriter(System.out); PrintWriter writer = new PrintWriter(System.out);
@ -192,20 +191,18 @@ public class GhidraScriptRunner implements GhidraLaunchable {
* Gather paths where scripts may be found. * Gather paths where scripts may be found.
*/ */
private void initializeScriptPaths() { private void initializeScriptPaths() {
List<BundlePath> paths; List<ResourceFile> paths;
if (scriptPaths == null || scriptPaths.isEmpty()) { if (scriptPaths == null || scriptPaths.isEmpty()) {
paths = GhidraScriptUtil.getDefaultScriptBundles(); paths = GhidraScriptUtil.getSystemScriptPaths();
paths.add(0, GhidraScriptUtil.getUserScriptDirectory());
} }
else { else {
paths = new ArrayList<>(); paths = new ArrayList<>();
for (String path : scriptPaths) { for (String path : scriptPaths) {
paths.add(new BundlePath(path, true, false, true)); paths.add(new ResourceFile(path));
}
for (BundlePath path : GhidraScriptUtil.getDefaultScriptBundles()) {
if (path.isEnabled() && !paths.contains(path)) {
paths.add(path);
}
} }
paths.addAll(GhidraScriptUtil.getSystemScriptPaths());
paths.add(0, GhidraScriptUtil.getUserScriptDirectory());
} }
GhidraScriptUtil.setScriptBundlePaths(paths); GhidraScriptUtil.setScriptBundlePaths(paths);

View file

@ -26,7 +26,6 @@ import generic.util.Path;
import ghidra.GhidraApplicationLayout; import ghidra.GhidraApplicationLayout;
import ghidra.GhidraJarApplicationLayout; import ghidra.GhidraJarApplicationLayout;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager; import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.app.plugin.core.script.osgi.BundlePath;
import ghidra.app.script.*; import ghidra.app.script.*;
import ghidra.app.util.headless.HeadlessScript.HeadlessContinuationOption; import ghidra.app.util.headless.HeadlessScript.HeadlessContinuationOption;
import ghidra.app.util.importer.AutoImporter; import ghidra.app.util.importer.AutoImporter;
@ -661,20 +660,18 @@ public class HeadlessAnalyzer {
*/ */
private void initializeScriptPaths() { private void initializeScriptPaths() {
List<BundlePath> paths; List<ResourceFile> paths;
if (options.scriptPaths == null || options.scriptPaths.isEmpty()) { if (options.scriptPaths == null || options.scriptPaths.isEmpty()) {
paths = GhidraScriptUtil.getDefaultScriptBundles(); paths = GhidraScriptUtil.getSystemScriptPaths();
paths.add(0, GhidraScriptUtil.getUserScriptDirectory());
} }
else { else {
paths = new ArrayList<>(); paths = new ArrayList<>();
for (String path : options.scriptPaths) { for (String path : options.scriptPaths) {
paths.add(new BundlePath(path, true, false, true)); paths.add(new ResourceFile(path));
}
for (BundlePath path : GhidraScriptUtil.getDefaultScriptBundles()) {
if (path.isEnabled() && !paths.contains(path)) {
paths.add(path);
}
} }
paths.addAll(GhidraScriptUtil.getSystemScriptPaths());
paths.add(0, GhidraScriptUtil.getUserScriptDirectory());
} }
GhidraScriptUtil.setScriptBundlePaths(paths); GhidraScriptUtil.setScriptBundlePaths(paths);

View file

@ -48,7 +48,6 @@ import generic.jar.ResourceFile;
import generic.test.TestUtils; import generic.test.TestUtils;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.console.ConsoleComponentProvider; import ghidra.app.plugin.core.console.ConsoleComponentProvider;
import ghidra.app.plugin.core.script.osgi.BundlePath;
import ghidra.app.plugin.core.script.osgi.BundleStatusProvider; import ghidra.app.plugin.core.script.osgi.BundleStatusProvider;
import ghidra.app.script.*; import ghidra.app.script.*;
import ghidra.app.services.ConsoleService; import ghidra.app.services.ConsoleService;
@ -979,10 +978,10 @@ public abstract class AbstractGhidraScriptMgrPluginTest
// destroy any NewScriptxxx files...and Temp ones too // destroy any NewScriptxxx files...and Temp ones too
BundleStatusProvider bundleStatusProvider = BundleStatusProvider bundleStatusProvider =
(BundleStatusProvider) TestUtils.getInstanceField("bundlePathManager", provider); (BundleStatusProvider) TestUtils.getInstanceField("bundleStatusProvider", provider);
List<BundlePath> paths = bundleStatusProvider.getModel().getPaths(); List<ResourceFile> paths = bundleStatusProvider.getModel().getPaths();
for (BundlePath path : paths) { for (ResourceFile path : paths) {
File file = path.getPath().getFile(false); File file = path.getFile(false);
File[] listFiles = file.listFiles(); File[] listFiles = file.listFiles();
if (listFiles == null) { if (listFiles == null) {
continue; continue;

View file

@ -19,9 +19,7 @@ import static org.junit.Assert.*;
import java.awt.event.InputEvent; import java.awt.event.InputEvent;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import javax.swing.*; import javax.swing.*;
@ -32,7 +30,6 @@ import docking.action.DockingActionIf;
import docking.widgets.filter.FilterTextField; import docking.widgets.filter.FilterTextField;
import docking.widgets.list.ListPanel; import docking.widgets.list.ListPanel;
import generic.jar.ResourceFile; import generic.jar.ResourceFile;
import ghidra.app.plugin.core.script.osgi.BundlePath;
import ghidra.app.plugin.core.script.osgi.BundleStatusProvider; import ghidra.app.plugin.core.script.osgi.BundleStatusProvider;
import ghidra.app.script.GhidraScriptUtil; import ghidra.app.script.GhidraScriptUtil;
import ghidra.app.script.JavaScriptProvider; import ghidra.app.script.JavaScriptProvider;
@ -286,13 +283,11 @@ public class GhidraScriptMgrPlugin3Test extends AbstractGhidraScriptMgrPluginTes
final BundleStatusProvider bundleStatusProvider = waitForComponentProvider(BundleStatusProvider.class); final BundleStatusProvider bundleStatusProvider = waitForComponentProvider(BundleStatusProvider.class);
final File dir = new File(getTestDirectoryPath() + "/test_scripts"); final ResourceFile dir = new ResourceFile(getTestDirectoryPath() + "/test_scripts");
dir.mkdirs(); dir.getFile(false).mkdirs();
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
List<BundlePath> paths = bundleStatusProvider.getModel().getPaths(); bundleStatusProvider.getModel().insertPathForTesting(0, dir.getAbsolutePath());
paths.add(0, new BundlePath(dir));
bundleStatusProvider.getModel().setPaths(paths);
}); });
waitForSwing(); waitForSwing();
@ -333,7 +328,7 @@ public class GhidraScriptMgrPlugin3Test extends AbstractGhidraScriptMgrPluginTes
assertTrue(newScript.exists()); assertTrue(newScript.exists());
assertNotNull(newScript); assertNotNull(newScript);
assertEquals(dir, newScript.getParentFile().getFile(false)); assertEquals(dir.getAbsolutePath(), newScript.getParentFile().getFile(false).getAbsolutePath());
newScript.delete(); newScript.delete();
dir.delete(); dir.delete();

View file

@ -28,7 +28,6 @@ import docking.widgets.tree.GTreeNode;
import generic.jar.ResourceFile; import generic.jar.ResourceFile;
import ghidra.app.plugin.core.console.ConsoleComponentProvider; import ghidra.app.plugin.core.console.ConsoleComponentProvider;
import ghidra.app.plugin.core.script.*; import ghidra.app.plugin.core.script.*;
import ghidra.app.plugin.core.script.osgi.BundlePath;
import ghidra.app.plugin.core.script.osgi.BundleStatusProvider; import ghidra.app.plugin.core.script.osgi.BundleStatusProvider;
import ghidra.app.script.GhidraScriptUtil; import ghidra.app.script.GhidraScriptUtil;
import ghidra.app.services.ConsoleService; import ghidra.app.services.ConsoleService;
@ -50,10 +49,10 @@ public class GhidraScriptMgrPluginScreenShots extends GhidraScreenShotGenerator
performAction("New", "GhidraScriptMgrPlugin", false); performAction("New", "GhidraScriptMgrPlugin", false);
JDialog d = waitForJDialog(null, "New Script: Type", 5000); JDialog d = waitForJDialog("New Script: Type");
pressButtonByText(d, "OK"); pressButtonByText(d, "OK");
d = waitForJDialog(null, "New Script", 5000); d = waitForJDialog("New Script");
pressButtonByText(d, "OK"); pressButtonByText(d, "OK");
captureIsolatedProvider(GhidraScriptEditorComponentProvider.class, 597, 600); captureIsolatedProvider(GhidraScriptEditorComponentProvider.class, 597, 600);
@ -111,13 +110,13 @@ public class GhidraScriptMgrPluginScreenShots extends GhidraScreenShotGenerator
@Test @Test
public void testScript_Dirs() throws Exception { public void testScript_Dirs() throws Exception {
List<BundlePath> paths = new ArrayList<>(); List<String> paths = new ArrayList<>();
paths.add(new BundlePath("$USER_HOME/ghidra_scripts")); paths.add("$USER_HOME/ghidra_scripts");
paths.add(new BundlePath("$GHIDRA_HOME/Features/Base/ghidra_scripts")); paths.add("$GHIDRA_HOME/Features/Base/ghidra_scripts");
paths.add(new BundlePath("/User/defined/invalid/directory")); paths.add("/User/defined/invalid/directory");
BundleStatusProvider bundleStatusProvider = showProvider(BundleStatusProvider.class); BundleStatusProvider bundleStatusProvider = showProvider(BundleStatusProvider.class);
bundleStatusProvider.getModel().setPaths(paths); bundleStatusProvider.getModel().setPathsForTesting(paths);
waitForComponentProvider(BundleStatusProvider.class); waitForComponentProvider(BundleStatusProvider.class);
captureComponent(bundleStatusProvider.getComponent()); captureComponent(bundleStatusProvider.getComponent());