allow failing scripts

This commit is contained in:
Jason P. Leasure
2020-02-12 15:15:36 -05:00
parent 59bd3806cc
commit d5d75fac9f
6 changed files with 154 additions and 111 deletions

View File

@@ -1,10 +1,10 @@
##VERSION: 2.0
##MODULE IP: BSD
##MODULE IP: MIT
##MODULE IP: Apache License 2.0
##MODULE IP: BSD
##MODULE IP: Copyright Distribution Permitted
##MODULE IP: FAMFAMFAM Icons - CC 2.5
##MODULE IP: LGPL 2.1
##MODULE IP: MIT
##MODULE IP: Modified Nuvola Icons - LGPL 2.1
##MODULE IP: Nuvola Icons - LGPL 2.1
##MODULE IP: Oxygen Icons - LGPL 3.0

View File

@@ -130,8 +130,11 @@ public class JavaScriptProvider extends GhidraScriptProvider {
bundle_host.startBundleWatcher();
}
// wait for bundle to be started
try {
Bundle b = bundle_host.installExplodedPath(bi.binDir);
bi.bundleLoc = b.getLocation();
System.err.printf("new bundle loc is %s\n", bi.bundleLoc);
b.start();
if (!bundle_host.waitForBundleStart(bi.bundleLoc)) {
Msg.error(this, "starting bundle");
return null;
@@ -187,7 +190,7 @@ public class JavaScriptProvider extends GhidraScriptProvider {
final ResourceFile sourceDir;
final String symbolicName;
final Path binDir;
final String bundleLoc;
String bundleLoc;
public ScriptBundleInfo(ResourceFile sourceDir) {
this.sourceDir = sourceDir;

View File

@@ -43,6 +43,10 @@ public class ResourceFileJavaFileObject implements JavaFileObject {
pathName = file.getAbsolutePath().substring(sourceRootPath.length() + 1);
}
public ResourceFile getFile() {
return file;
}
@Override
public URI toUri() {
return file.toURI();

View File

@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.script.osgi;
import java.io.*;
@@ -35,6 +34,7 @@ import aQute.bnd.osgi.*;
import aQute.bnd.osgi.Clazz.QUERY;
import generic.jar.ResourceFile;
import ghidra.app.script.*;
import ghidra.util.Msg;
public class BundleCompiler {
@@ -44,10 +44,11 @@ public class BundleCompiler {
this.bh = bh;
}
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// compile a source directory to an exploded bundle
public void compileToExplodedBundle(ResourceFile srcdir, Path bindir, Writer output)
public void compileToExplodedBundle(ResourceFile srcdir, Path bindir, Writer writer)
throws IOException {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
List<String> options = new ArrayList<>();
options.add("-g");
options.add("-d");
@@ -60,7 +61,6 @@ public class BundleCompiler {
final JavaFileManager fm0 =
new ResourceFileJavaFileManager(GhidraScriptUtil.getScriptSourceDirectories());
BundleJavaManager fm = new BundleJavaManager(bh.getHostFramework(), fm0, options);
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
final List<ResourceFileJavaFileObject> compilationUnits = new ArrayList<>();
@@ -76,29 +76,54 @@ public class BundleCompiler {
Files.delete(dmf);
}
JavaCompiler.CompilationTask task =
compiler.getTask(output, fm, diagnostics, options, null, compilationUnits);
// task.setProcessors // for annotation processing / code generation
// try to compile, if we fail remove offenders and try again
while (!compilationUnits.isEmpty()) {
DiagnosticCollector<JavaFileObject> diagnostics =
new DiagnosticCollector<JavaFileObject>();
JavaCompiler.CompilationTask task =
compiler.getTask(writer, fm, diagnostics, options, null, compilationUnits);
// task.setProcessors // for annotation processing / code generation
Boolean successfulCompilation = task.call();
output.flush();
System.err.printf("%s: %s\n", successfulCompilation ? "Success" : "Fail", output);
if (successfulCompilation) {
ResourceFile smf =
new ResourceFile(srcdir, "META-INF" + File.separator + "MANIFEST.MF");
if (smf.exists()) {
System.err.printf("Found manifest, not generating one\n");
Files.createFile(dmf);
Files.copy(smf.getInputStream(), dmf, StandardCopyOption.REPLACE_EXISTING);
return;
Boolean successfulCompilation = task.call();
if (successfulCompilation) {
break;
}
for (Diagnostic<? extends JavaFileObject> d : diagnostics.getDiagnostics()) {
writer.write(d.getSource().toString() + ": " + d.getMessage(null) + "\n");
ResourceFileJavaFileObject sf = (ResourceFileJavaFileObject) d.getSource();
if (compilationUnits.remove(sf)) {
writer.write(String.format("skipping %s\n", sf.toString()));
ResourceFile rf = sf.getFile();
if (GhidraScriptUtil.contains(rf)) {
ScriptInfo info = GhidraScriptUtil.getScriptInfo(rf);
info.setCompileErrors(true);
}
}
}
}
// make sure the succeses are marked
for (ResourceFileJavaFileObject sf : compilationUnits) {
ResourceFile rf = sf.getFile();
if (GhidraScriptUtil.contains(rf)) {
ScriptInfo info = GhidraScriptUtil.getScriptInfo(rf);
info.setCompileErrors(false);
}
}
// no manifest, so create one with bndtools
Analyzer analyzer = new Analyzer();
analyzer.setJar(new Jar(bindir.toFile())); // give bnd the contents
Stream<Object> bjars = Files.list(bh.getCompiledBundlesDir()).filter(
f -> f.toString().endsWith(".jar")).map(f -> {
ResourceFile smf = new ResourceFile(srcdir, "META-INF" + File.separator + "MANIFEST.MF");
if (smf.exists()) {
System.err.printf("Found manifest, not generating one\n");
Files.createFile(dmf);
Files.copy(smf.getInputStream(), dmf, StandardCopyOption.REPLACE_EXISTING);
return;
}
// no manifest, so create one with bndtools
Analyzer analyzer = new Analyzer();
analyzer.setJar(new Jar(bindir.toFile())); // give bnd the contents
Stream<Object> bjars =
Files.list(bh.getCompiledBundlesDir()).filter(f -> f.toString().endsWith(".jar")).map(
f -> {
try {
return new Jar(f.toFile());
}
@@ -108,91 +133,99 @@ public class BundleCompiler {
}
});
analyzer.addClasspath(bjars.collect(Collectors.toUnmodifiableList()));
analyzer.setProperty("Bundle-SymbolicName",
JavaScriptProvider.getSymbolicNameFromSourceDir(srcdir));
analyzer.setProperty("Bundle-Version", "1.0");
analyzer.setProperty("Import-Package", "*");
// analyzer.setBundleActivator(s);
analyzer.addClasspath(bjars.collect(Collectors.toUnmodifiableList()));
analyzer.setProperty("Bundle-SymbolicName",
JavaScriptProvider.getSymbolicNameFromSourceDir(srcdir));
analyzer.setProperty("Bundle-Version", "1.0");
analyzer.setProperty("Import-Package", "*");
// analyzer.setBundleActivator(s);
try {
Manifest manifest = analyzer.calcManifest();
Attributes ma = manifest.getMainAttributes();
try {
Manifest manifest = analyzer.calcManifest();
Attributes ma = manifest.getMainAttributes();
String activator_classname = null;
for (Clazz clazz : analyzer.getClassspace().values()) {
if (clazz.is(QUERY.IMPLEMENTS,
new Instruction("org.osgi.framework.BundleActivator"), analyzer)) {
System.err.printf("found BundleActivator class %s\n", clazz);
activator_classname = clazz.toString();
}
}
if (activator_classname == null) {
Path activator_dest = bindir.resolve("GeneratedActivator.java");
try (PrintWriter writer = new PrintWriter(
Files.newBufferedWriter(activator_dest, Charset.forName("UTF-8")))) {
writer.println("import ghidra.app.script.osgi.GhidraBundleActivator;");
writer.println("import org.osgi.framework.BundleActivator;");
writer.println("import org.osgi.framework.BundleContext;");
writer.println(
"public class GeneratedActivator extends GhidraBundleActivator {");
writer.println(" protected void start(BundleContext bc, Object api) {");
writer.println(" // TODO: stuff to do on bundle start");
writer.println(" }");
writer.println(" protected void stop(BundleContext bc, Object api) {");
writer.println(" // TODO: stuff to do on bundle stop");
writer.println(" }");
writer.println();
writer.println("}");
}
catch (IOException ex) {
ex.printStackTrace();
return;
}
activator_classname = "GeneratedActivator";
options.clear();
options.add("-g");
options.add("-d");
options.add(bindir.toString());
options.add("-sourcepath");
options.add(bindir.toString());
options.add("-classpath");
options.add(System.getProperty("java.class.path"));
options.add("-proc:none");
StandardJavaFileManager fm02 =
compiler.getStandardFileManager(null, null, null);
fm = new BundleJavaManager(bh.getHostFramework(), fm02, options);
Iterable<? extends JavaFileObject> compilationUnits2 =
fm02.getJavaFileObjectsFromPaths(List.of(activator_dest));
JavaCompiler.CompilationTask task2 =
compiler.getTask(output, fm, diagnostics, options, null, compilationUnits2);
if (!task2.call()) {
return;
}
// since we add the activator after bndtools built the imports, we should add its imports too
String imps = ma.getValue(Constants.IMPORT_PACKAGE);
ma.putValue(Constants.IMPORT_PACKAGE, imps + ",ghidra.app.script.osgi");
}
ma.putValue(Constants.BUNDLE_ACTIVATOR, activator_classname);
Files.createDirectories(dmf.getParent());
try (OutputStream out = Files.newOutputStream(dmf)) {
manifest.write(out);
String activator_classname = null;
for (Clazz clazz : analyzer.getClassspace().values()) {
if (clazz.is(QUERY.IMPLEMENTS,
new Instruction("org.osgi.framework.BundleActivator"), analyzer)) {
System.err.printf("found BundleActivator class %s\n", clazz);
activator_classname = clazz.toString();
}
}
catch (Exception e) {
e.printStackTrace();
if (activator_classname == null) {
activator_classname = "GeneratedActivator";
if (!createActivator(bindir, activator_classname, writer)) {
Msg.error(this, "failed to create activator");
return;
}
// since we add the activator after bndtools built the imports, we should add its imports too
String imps = ma.getValue(Constants.IMPORT_PACKAGE);
ma.putValue(Constants.IMPORT_PACKAGE, imps + ",ghidra.app.script.osgi");
}
ma.putValue(Constants.BUNDLE_ACTIVATOR, activator_classname);
// write the manifest
Files.createDirectories(dmf.getParent());
try (OutputStream out = Files.newOutputStream(dmf)) {
manifest.write(out);
}
analyzer.close();
}
else {
for (Diagnostic<? extends JavaFileObject> dm : diagnostics.getDiagnostics()) {
System.err.printf("COMPILE ERROR: %s\n", dm);
}
catch (Exception e) {
e.printStackTrace();
}
finally {
analyzer.close();
}
}
private boolean createActivator(Path bindir, String activator_classname, Writer output)
throws IOException {
Path activator_dest = bindir.resolve(activator_classname + ".java");
try (PrintWriter writer =
new PrintWriter(Files.newBufferedWriter(activator_dest, Charset.forName("UTF-8")))) {
writer.println("import ghidra.app.script.osgi.GhidraBundleActivator;");
writer.println("import org.osgi.framework.BundleActivator;");
writer.println("import org.osgi.framework.BundleContext;");
writer.println("public class GeneratedActivator extends GhidraBundleActivator {");
writer.println(" protected void start(BundleContext bc, Object api) {");
writer.println(" // TODO: stuff to do on bundle start");
writer.println(" }");
writer.println(" protected void stop(BundleContext bc, Object api) {");
writer.println(" // TODO: stuff to do on bundle stop");
writer.println(" }");
writer.println();
writer.println("}");
}
catch (IOException ex) {
ex.printStackTrace();
return false;
}
List<String> options = new ArrayList<>();
options.add("-g");
options.add("-d");
options.add(bindir.toString());
options.add("-sourcepath");
options.add(bindir.toString());
options.add("-classpath");
options.add(System.getProperty("java.class.path"));
options.add("-proc:none");
StandardJavaFileManager fm0 = compiler.getStandardFileManager(null, null, null);
BundleJavaManager fm = new BundleJavaManager(bh.getHostFramework(), fm0, options);
Iterable<? extends JavaFileObject> compilationUnits2 =
fm0.getJavaFileObjectsFromPaths(List.of(activator_dest));
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
JavaCompiler.CompilationTask task2 =
compiler.getTask(output, fm, diagnostics, options, null, compilationUnits2);
if (!task2.call()) {
for (Diagnostic<? extends JavaFileObject> d : diagnostics.getDiagnostics()) {
output.write(d.getSource().toString() + ": " + d.getMessage(null) + "\n");
}
return false;
}
return true;
}
}

View File

@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.script.osgi;
import static java.util.stream.Collectors.*;
@@ -28,7 +27,6 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.felix.fileinstall.internal.FileInstall;
import org.apache.felix.framework.FrameworkFactory;
import org.apache.felix.framework.util.FelixConstants;
import org.apache.felix.main.AutoProcessor;
@@ -68,6 +66,11 @@ public class BundleHost {
return bc.installBundle(location, new FileInputStream(new File(path_to_jar)));
}
public Bundle installExplodedPath(Path p) throws BundleException {
return bc.installBundle("reference:file://" + p.toAbsolutePath().normalize().toString());
}
void dumpLoadedBundles() {
System.err.printf("=== Bundles ===\n");
for (Bundle bundle : bc.getBundles()) {
@@ -196,8 +199,9 @@ public class BundleHost {
});
felix.start();
fileinstall_bundle = installFromPath(findJarForClass(FileInstall.class));
fileinstall_bundle.start();
// fileinstall_bundle = installFromPath(findJarForClass(FileInstall.class));
// fileinstall_bundle.start();
}
private Path getOsgiDir() {

View File

@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.script.osgi;
import org.osgi.framework.BundleActivator;