mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-09-20 09:31:47 +00:00
GP-3430 - Updated the gradle buildHelp task to better handle its inputs up-do-date state
This commit is contained in:
parent
0d71657d05
commit
a7668c7f85
|
@ -127,7 +127,7 @@ if (System.env.LLVM_HOME) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println "Debugger-swig-lldb:buildNatives skipped - LLVM_HOME not defined"
|
logger.debug('Debugger-swig-lldb:buildNatives skipped - LLVM_HOME not defined')
|
||||||
}
|
}
|
||||||
|
|
||||||
task checkLLVM {
|
task checkLLVM {
|
||||||
|
|
|
@ -31,10 +31,6 @@ dependencies {
|
||||||
api project(':Decompiler')
|
api project(':Decompiler')
|
||||||
api project(':ProposedUtils')
|
api project(':ProposedUtils')
|
||||||
|
|
||||||
helpPath project(path: ':Base', configuration: 'helpPath')
|
|
||||||
helpPath project(path: ':Decompiler', configuration: 'helpPath')
|
|
||||||
helpPath project(path: ':ProgramDiff', configuration: 'helpPath')
|
|
||||||
|
|
||||||
testImplementation project(path: ':Base', configuration: 'testArtifacts')
|
testImplementation project(path: ':Base', configuration: 'testArtifacts')
|
||||||
testImplementation project(path: ':Framework-AsyncComm', configuration: 'testArtifacts')
|
testImplementation project(path: ':Framework-AsyncComm', configuration: 'testArtifacts')
|
||||||
testImplementation project(path: ':Framework-Debugging', configuration: 'testArtifacts')
|
testImplementation project(path: ':Framework-Debugging', configuration: 'testArtifacts')
|
||||||
|
|
|
@ -23,7 +23,6 @@ eclipse.project.name = 'Xtra MachineLearning'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api project(':Base')
|
api project(':Base')
|
||||||
helpPath project(path: ":Base", configuration: 'helpPath')
|
|
||||||
|
|
||||||
api "com.oracle.labs.olcut:olcut-config-protobuf:5.2.0" //{exclude group: "com.google.protobuf", module: "protobuf-java"}
|
api "com.oracle.labs.olcut:olcut-config-protobuf:5.2.0" //{exclude group: "com.google.protobuf", module: "protobuf-java"}
|
||||||
api ("com.oracle.labs.olcut:olcut-core:5.2.0") {exclude group: "org.jline"}
|
api ("com.oracle.labs.olcut:olcut-core:5.2.0") {exclude group: "org.jline"}
|
||||||
|
|
|
@ -61,7 +61,6 @@ dependencies {
|
||||||
testImplementation project(path: ':Project', configuration: 'testArtifacts')
|
testImplementation project(path: ':Project', configuration: 'testArtifacts')
|
||||||
testImplementation project(path: ':SoftwareModeling', configuration: 'testArtifacts')
|
testImplementation project(path: ':SoftwareModeling', configuration: 'testArtifacts')
|
||||||
testImplementation project(path: ':DB', configuration: 'testArtifacts')
|
testImplementation project(path: ':DB', configuration: 'testArtifacts')
|
||||||
helpPath project(path: ':Docking', configuration: 'helpPath') // this module's help has links to Base help files
|
|
||||||
|
|
||||||
javacc 'net.java.dev.javacc:javacc:5.0'
|
javacc 'net.java.dev.javacc:javacc:5.0'
|
||||||
}
|
}
|
||||||
|
@ -125,22 +124,29 @@ task buildJavacc {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: this must happen before the standard buildHelp for Base
|
// Note: this must happen before the standard buildHelp for Base
|
||||||
task generateExtraHelpFiles {
|
tasks.register('generateExtraHelpFiles') {
|
||||||
|
|
||||||
group = 'private'
|
group = 'private'
|
||||||
description " Creates any extra help files for Base not covered by the standard build help system"
|
description " Creates any extra help files for Base not covered by the standard build help system"
|
||||||
|
|
||||||
def rawTipsFile = file('src/main/resources/ghidra/app/plugin/core/totd/tips.txt')
|
def rawTipsFile = file('src/main/resources/ghidra/app/plugin/core/totd/tips.txt')
|
||||||
inputs.file(rawTipsFile)
|
inputs.file(rawTipsFile)
|
||||||
|
|
||||||
def htmlTipsFile = file('src/main/help/help/topics/Misc/Tips.htm')
|
def htmlTipsFile = file('build/help/main/help/topics/Misc/Tips.htm')
|
||||||
outputs.file(htmlTipsFile)
|
outputs.file(htmlTipsFile)
|
||||||
|
|
||||||
doLast {
|
doLast {
|
||||||
createTipsHelpFile(rawTipsFile, htmlTipsFile)
|
createTipsHelpFile(rawTipsFile, htmlTipsFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Base's help includes the file generated by the 'generateExtraHelpFiles' task. Signal that we
|
||||||
|
// depend on that task and it's output file.
|
||||||
|
tasks.named('buildHelp') {
|
||||||
|
dependsOn(tasks.named('generateExtraHelpFiles'))
|
||||||
|
inputs.files tasks.named('generateExtraHelpFiles').get().outputs
|
||||||
|
}
|
||||||
|
|
||||||
def createTipsHelpFile(input, output) {
|
def createTipsHelpFile(input, output) {
|
||||||
// transform original contents - wrap each line in <li> tags
|
// transform original contents - wrap each line in <li> tags
|
||||||
def buffy = new StringBuilder()
|
def buffy = new StringBuilder()
|
||||||
|
@ -169,7 +175,7 @@ def createTipsHelpFile(input, output) {
|
||||||
|
|
||||||
output.text = htmlContent
|
output.text = htmlContent
|
||||||
|
|
||||||
println '\n\n\nwrote file ' + output + '\n\n\n'
|
logger.info '\n\n\nwrote file ' + output + '\n\n\n'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,5 @@ eclipse.project.name = 'Features BytePatterns'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api project(':Base')
|
api project(':Base')
|
||||||
api project(':Utility')
|
api project(':Utility')
|
||||||
|
|
||||||
helpPath project(path: ":Base", configuration: 'helpPath')
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,4 @@ dependencies {
|
||||||
api project(':Base')
|
api project(':Base')
|
||||||
|
|
||||||
testImplementation project(path: ':SoftwareModeling', configuration: 'testArtifacts')
|
testImplementation project(path: ':SoftwareModeling', configuration: 'testArtifacts')
|
||||||
|
|
||||||
helpPath project(path: ':Base', configuration: 'helpPath') // this module's help has links to Base help files
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,8 +32,6 @@ dependencies {
|
||||||
// include Base src/test/resources when running decompiler integration tests (uses defaultTools)
|
// include Base src/test/resources when running decompiler integration tests (uses defaultTools)
|
||||||
integrationTestImplementation project(path: ':Base', configuration: 'testArtifacts')
|
integrationTestImplementation project(path: ':Base', configuration: 'testArtifacts')
|
||||||
integrationTestImplementation project(path: ':SoftwareModeling', configuration: 'testArtifacts')
|
integrationTestImplementation project(path: ':SoftwareModeling', configuration: 'testArtifacts')
|
||||||
|
|
||||||
helpPath project(path: ":Base", configuration: 'helpPath')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Include buildable native source in distribution
|
// Include buildable native source in distribution
|
||||||
|
|
|
@ -47,8 +47,6 @@ dependencies {
|
||||||
api 'net.sf.sevenzipjbinding:sevenzipjbinding:16.02-2.01'
|
api 'net.sf.sevenzipjbinding:sevenzipjbinding:16.02-2.01'
|
||||||
runtimeOnly 'net.sf.sevenzipjbinding:sevenzipjbinding-all-platforms:16.02-2.01'
|
runtimeOnly 'net.sf.sevenzipjbinding:sevenzipjbinding-all-platforms:16.02-2.01'
|
||||||
|
|
||||||
helpPath project(path: ":Base", configuration: 'helpPath')
|
|
||||||
|
|
||||||
// include code from src/test/slow in Base
|
// include code from src/test/slow in Base
|
||||||
testImplementation project(path: ':Base', configuration: 'integrationTestArtifacts')
|
testImplementation project(path: ':Base', configuration: 'integrationTestArtifacts')
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,15 +22,9 @@ apply plugin: 'eclipse'
|
||||||
|
|
||||||
eclipse.project.name = 'Features Graph FunctionGraph'
|
eclipse.project.name = 'Features Graph FunctionGraph'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
api project(":Base")
|
api project(":Base")
|
||||||
|
|
||||||
api project(":GraphServices")
|
api project(":GraphServices")
|
||||||
|
|
||||||
helpPath project(path: ":Base", configuration: 'helpPath')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -770,10 +770,6 @@
|
||||||
mouse scroll wheel. Disabling this option restores the original function graph scroll wheel
|
mouse scroll wheel. Disabling this option restores the original function graph scroll wheel
|
||||||
behavior of zooming when scrolled.</P>
|
behavior of zooming when scrolled.</P>
|
||||||
|
|
||||||
<P>The <B>Start Fully Zoomed Out</B> option causes the initial graph to zoom out far enough
|
|
||||||
that the entire graph is displayed. When this option is off a new graph rendering will zoom
|
|
||||||
all the way in (no scaling) to the active vertex.</P>
|
|
||||||
|
|
||||||
<P>The <B>Update Vertex Colors When Grouping</B> option signals to the graph to make the
|
<P>The <B>Update Vertex Colors When Grouping</B> option signals to the graph to make the
|
||||||
color of the grouped vertex be that of the vertices being grouped.</P>
|
color of the grouped vertex be that of the vertices being grouped.</P>
|
||||||
|
|
||||||
|
|
|
@ -26,9 +26,7 @@ eclipse.project.name = 'Features FunctionID'
|
||||||
dependencies {
|
dependencies {
|
||||||
api project(":Base")
|
api project(":Base")
|
||||||
api project(":DB")
|
api project(":DB")
|
||||||
api project(":SoftwareModeling")
|
api project(":SoftwareModeling")
|
||||||
helpPath project(path: ":Base", configuration: 'helpPath')
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// All *.fidb files located in the dependencies/fid directory OR the
|
// All *.fidb files located in the dependencies/fid directory OR the
|
||||||
|
|
|
@ -26,14 +26,7 @@ eclipse.project.name = 'Features Graph FunctionCalls'
|
||||||
// Note: this module's name is 'GraphFunctionCalls'
|
// Note: this module's name is 'GraphFunctionCalls'
|
||||||
dependencies {
|
dependencies {
|
||||||
api project(":Base")
|
api project(":Base")
|
||||||
|
|
||||||
helpPath project(path: ":Base", configuration: 'helpPath')
|
|
||||||
|
|
||||||
// This is needed now because we like to the help of the FunctionGraph. If and when that
|
|
||||||
// help is extracted to a higher-level help page, like 'Graphing', then this link should be
|
|
||||||
// removed
|
|
||||||
helpPath project(path: ":FunctionGraph", configuration: 'helpPath')
|
|
||||||
|
|
||||||
// These have abstract test classes and stubs needed by this module
|
// These have abstract test classes and stubs needed by this module
|
||||||
testImplementation project(path: ':Project', configuration: 'testArtifacts')
|
testImplementation project(path: ':Project', configuration: 'testArtifacts')
|
||||||
testImplementation project(path: ':SoftwareModeling', configuration: 'testArtifacts')
|
testImplementation project(path: ':SoftwareModeling', configuration: 'testArtifacts')
|
||||||
|
|
|
@ -226,20 +226,88 @@
|
||||||
<H2><A name="Satellite_View"></A>Satellite View</H2>
|
<H2><A name="Satellite_View"></A>Satellite View</H2>
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<P>The Satellite View works exactly as the
|
<P>The Satellite View provides an overview of the graph. From this view you may also perform
|
||||||
<A href="help/topics/FunctionGraphPlugin/Function_Graph.html#Satellite_View">
|
basic adjustment of the overall graph location. In addition to the complete graph, the
|
||||||
Function Graph's Satellite View</A>.
|
satellite view contains a <B>lens</B> (the white rectangle) that indicates how much of the
|
||||||
</P>
|
current graph fits into the primary view.</P>
|
||||||
</BLOCKQUOTE>
|
|
||||||
|
<P>When you single left mouse click in the satellite view the graph is centered around the
|
||||||
|
corresponding point in the primary view. Alternatively, you may drag the lens of the
|
||||||
|
satellite view to the desired location by performing a mouse drag operation on the lens.</P>
|
||||||
|
|
||||||
|
<P>You may hide the satellite view by right-clicking anywhere in the Primary View and
|
||||||
|
deselecting the <B>Display Satellite View</B> toggle button from the popup menu.</P>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P><IMG src="help/shared/tip.png" alt="" border="0"> If the Primary View is painting
|
||||||
|
sluggishly, then hiding the Satellite View cause the Primary View to be more
|
||||||
|
responsive.</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<H3><A name="Satellite_View_Dock"></A>Detached Satellite</H3>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>The Satellite View is attached, or <B>docked</B>, to the Primary View by default.
|
||||||
|
However, you can detach, or undock, the Satellite View, which will put the view into a
|
||||||
|
Component Provider, which itself can be moved, resized and docked anywhere in the Tool you
|
||||||
|
wish.</P>
|
||||||
|
|
||||||
|
<P>To undock the Satellite View, right-click in the graph and deselect the <B>Dock
|
||||||
|
Satellite View</B> menu item.</P>
|
||||||
|
|
||||||
|
<P>To re-dock the Satellite View, right-click in the graph and select the <B>Dock Satellite
|
||||||
|
View</B> menu item.</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P><IMG src="help/shared/tip.png" alt="" border="0"> To reshow the Satellite View if it is
|
||||||
|
hidden, whether docked or undocked, you can press the <IMG src=
|
||||||
|
"images/network-wireless.png" alt="" border="1"> button. This button is in the lower-right
|
||||||
|
hand corner of the graph and is only visible if the Satellite View is hidden or
|
||||||
|
undocked.</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<H2><A name="Options"></A>Options</H2>
|
<H2><A name="Options"></A>Options</H2>
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<P>The Function Call Graph options are currently a subset of the
|
|
||||||
<A href="help/topics/FunctionGraphPlugin/Function_Graph.html#Options">
|
<P>The <B>Scroll Wheel Pans</B> option signals to move the graph vertical when scrolling the
|
||||||
Function Graph's Options</A>.
|
mouse scroll wheel. Disabling this option restores the original function graph scroll wheel
|
||||||
</P>
|
behavior of zooming when scrolled.</P>
|
||||||
</BLOCKQUOTE>
|
|
||||||
|
<P>The <B>Use Animation</B> option signals to the graph whether to animate mutative graph
|
||||||
|
operations and navigations.</P>
|
||||||
|
|
||||||
|
<P><A name="Layout_Compressing"></A>The <B>Use Condensed Layout</B> option signals to the
|
||||||
|
graph to bring vertices as close together as possible when laying out the graph. Using this
|
||||||
|
option to fit as many vertices on the screen as possible. Disable this option to make the
|
||||||
|
overall layout of the graph more aesthetic.</P>
|
||||||
|
|
||||||
|
<P>The <B>Use Mouse-relative Zoom</B> option signals zoom the graph to and from the mouse
|
||||||
|
location when zooming from the middle-mouse. The default for this option is off, which
|
||||||
|
triggers zoom to work from the center of the graph, regardless of the mouse location.</P>
|
||||||
|
|
||||||
|
<P>The <B>View Settings</B> option describes how the graph will be zoomed when it is first
|
||||||
|
loaded. The values are:</P>
|
||||||
|
|
||||||
|
<UL>
|
||||||
|
<LI><B>Start Fully Zoomed Out</B> - always start fully zoomed out so that the entire
|
||||||
|
graph can be seen.</LI>
|
||||||
|
|
||||||
|
<LI><B>Start Fully Zoomed In</B> - always start fully zoomed in on the vertex containing
|
||||||
|
the current location.</LI>
|
||||||
|
|
||||||
|
<LI><B>Remember User Settings</B> - keep the zoom level where the user previously left
|
||||||
|
it.</LI>
|
||||||
|
</UL>
|
||||||
|
<BR>
|
||||||
|
<BR>
|
||||||
|
|
||||||
|
<P>There are various edge color and highlight color options available to change. The
|
||||||
|
highlight colors are those to be used when the flow animations take place.</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
|
@ -36,8 +36,5 @@ dependencies {
|
||||||
api ("org.jgrapht:jgrapht-io:1.5.1") { exclude group: "org.antlr", module: "antlr4-runtime" }
|
api ("org.jgrapht:jgrapht-io:1.5.1") { exclude group: "org.antlr", module: "antlr4-runtime" }
|
||||||
|
|
||||||
runtimeOnly "org.jheaps:jheaps:0.13"
|
runtimeOnly "org.jheaps:jheaps:0.13"
|
||||||
|
|
||||||
helpPath project(path: ":Base", configuration: 'helpPath')
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,8 +33,7 @@ dependencies {
|
||||||
|
|
||||||
// Demangler Analyzer needs to find MicrosoftDemangler
|
// Demangler Analyzer needs to find MicrosoftDemangler
|
||||||
api project(":MicrosoftDemangler")
|
api project(":MicrosoftDemangler")
|
||||||
helpPath project(path: ':Base', configuration: 'helpPath') // this module's help has links to Base help files
|
|
||||||
|
|
||||||
testImplementation project(path: ':Base', configuration: 'testArtifacts')
|
testImplementation project(path: ':Base', configuration: 'testArtifacts')
|
||||||
testImplementation project(path: ':SoftwareModeling', configuration: 'testArtifacts')
|
testImplementation project(path: ':SoftwareModeling', configuration: 'testArtifacts')
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,4 @@ eclipse.project.name = 'Features ProgramDiff'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api project(":Base")
|
api project(":Base")
|
||||||
helpPath project(path: ":Base", configuration: 'helpPath')
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,9 +25,6 @@ eclipse.project.name = 'Features Graph ProgramGraph'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api project(":Base")
|
api project(":Base")
|
||||||
|
api project(":GraphServices")
|
||||||
helpPath project(path: ":Base", configuration: 'helpPath')
|
|
||||||
helpPath project(path: ":GraphServices", configuration: 'helpPath')
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -495,8 +495,7 @@
|
||||||
<P>These are the display options for graphs that are types of "Program Graphs" such as
|
<P>These are the display options for graphs that are types of "Program Graphs" such as
|
||||||
Call graphs, Block graphs, etc. These types of graphs
|
Call graphs, Block graphs, etc. These types of graphs
|
||||||
use program elements as vertices and reference types as edges. See
|
use program elements as vertices and reference types as edges. See
|
||||||
<A href="help/topics/GraphServices/GraphDisplay.htm#Graph_Type_Display_Options">Graph Type Display Options</A> for
|
<B>Graph Type Display Options</B> for general help on graph type display options.</P>
|
||||||
general help on graph type display options.</P>
|
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
<P class="providedbyplugin">Provided by: <I>Program Graph Plugin</I></P>
|
<P class="providedbyplugin">Provided by: <I>Program Graph Plugin</I></P>
|
||||||
|
|
||||||
|
|
|
@ -33,8 +33,7 @@ configurations {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api project(':Base')
|
api project(':Base')
|
||||||
helpPath project(path: ":Base", configuration: "helpPath")
|
jython JYTHON
|
||||||
jython JYTHON
|
|
||||||
api JYTHON
|
api JYTHON
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,5 +25,4 @@ eclipse.project.name = 'Features SourceCodeLookup'
|
||||||
dependencies {
|
dependencies {
|
||||||
api project(":Base")
|
api project(":Base")
|
||||||
api project(":Decompiler")
|
api project(":Decompiler")
|
||||||
helpPath project(path: ":Decompiler", configuration: 'helpPath')
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,6 @@ project.ext.excludeFromParallelIntegrationTests = true
|
||||||
dependencies {
|
dependencies {
|
||||||
api project(":Base")
|
api project(":Base")
|
||||||
|
|
||||||
helpPath project(path: ":Base", configuration: "helpPath")
|
|
||||||
|
|
||||||
testImplementation project(path: ':Project', configuration: 'testArtifacts')
|
testImplementation project(path: ':Project', configuration: 'testArtifacts')
|
||||||
testImplementation project(path: ':SoftwareModeling', configuration: 'testArtifacts')
|
testImplementation project(path: ':SoftwareModeling', configuration: 'testArtifacts')
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,4 @@ dependencies {
|
||||||
// Only include this debug version of the jh library if necessary.
|
// Only include this debug version of the jh library if necessary.
|
||||||
//api name:'jh2.with.debug'
|
//api name:'jh2.with.debug'
|
||||||
api 'javax.help:javahelp:2.0.05'
|
api 'javax.help:javahelp:2.0.05'
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -357,17 +357,6 @@ public class GHelpBuilder {
|
||||||
errorMessage(buffy.toString());
|
errorMessage(buffy.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void warningMessage(String... message) {
|
|
||||||
StringBuilder buffy = new StringBuilder();
|
|
||||||
buffy.append("\n");
|
|
||||||
buffy.append(" !!!!! WARNING !!!!!\n");
|
|
||||||
for (String string : message) {
|
|
||||||
buffy.append('\t').append('\t').append(string).append('\n');
|
|
||||||
}
|
|
||||||
buffy.append("\n");
|
|
||||||
errorMessage(buffy.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void printErrorMessage(String message) {
|
private static void printErrorMessage(String message) {
|
||||||
// this prevents error messages getting interspersed with output messages
|
// this prevents error messages getting interspersed with output messages
|
||||||
flush();
|
flush();
|
||||||
|
|
|
@ -68,7 +68,11 @@ public class HelpBuildUtils {
|
||||||
return new DirectoryHelpModuleLocation(file);
|
return new DirectoryHelpModuleLocation(file);
|
||||||
}
|
}
|
||||||
else if (file.isFile()) {
|
else if (file.isFile()) {
|
||||||
return new JarHelpModuleLocation(file);
|
JarHelpModuleLocation jarLocation = JarHelpModuleLocation.fromFile(file);
|
||||||
|
if (jarLocation == null) {
|
||||||
|
HelpBuildUtils.debug("Jar file does not contain help: " + file);
|
||||||
|
}
|
||||||
|
return jarLocation;
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Don't know how to create a help module location for file: " + file);
|
"Don't know how to create a help module location for file: " + file);
|
||||||
|
|
|
@ -15,16 +15,16 @@
|
||||||
*/
|
*/
|
||||||
package help;
|
package help;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
import help.validator.LinkDatabase;
|
import help.validator.LinkDatabase;
|
||||||
import help.validator.location.HelpModuleCollection;
|
import help.validator.location.HelpModuleCollection;
|
||||||
import help.validator.model.AnchorDefinition;
|
import help.validator.model.AnchorDefinition;
|
||||||
import help.validator.model.GhidraTOCFile;
|
import help.validator.model.GhidraTOCFile;
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.nio.file.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class:
|
* This class:
|
||||||
* <ul>
|
* <ul>
|
||||||
|
@ -129,7 +129,8 @@ public class JavaHelpFilesBuilder {
|
||||||
PrintWriter out = new LogFileWriter(mapFile);
|
PrintWriter out = new LogFileWriter(mapFile);
|
||||||
try {
|
try {
|
||||||
out.println("<?xml version='1.0' encoding='ISO-8859-1' ?>");
|
out.println("<?xml version='1.0' encoding='ISO-8859-1' ?>");
|
||||||
out.println("<!doctype MAP public \"-//Sun Microsystems Inc.//DTD JavaHelp Map Version 1.0//EN\">");
|
out.println(
|
||||||
|
"<!doctype MAP public \"-//Sun Microsystems Inc.//DTD JavaHelp Map Version 1.0//EN\">");
|
||||||
out.println("<!-- Auto-generated on " + (new Date()).toString() + " : Do Not Edit -->");
|
out.println("<!-- Auto-generated on " + (new Date()).toString() + " : Do Not Edit -->");
|
||||||
out.println("<map version=\"1.0\">");
|
out.println("<map version=\"1.0\">");
|
||||||
|
|
||||||
|
@ -166,8 +167,8 @@ public class JavaHelpFilesBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parent.endsWith("help")) {
|
if (!parent.endsWith("help")) {
|
||||||
throw new AssertException("Map file expected in a directory name 'help'. "
|
throw new AssertException("Map file expected in a directory name 'help'. " +
|
||||||
+ "Update the map file generation code.");
|
"Update the map file generation code.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!anchorTarget.startsWith("help")) {
|
if (!anchorTarget.startsWith("help")) {
|
||||||
|
|
|
@ -92,8 +92,11 @@ public class UnusedHelpImageFileFinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
SortedSet<Path> set =
|
SortedSet<Path> set =
|
||||||
new TreeSet<>((f1, f2) -> f1.toUri().toString().toLowerCase().compareTo(
|
new TreeSet<>((f1, f2) -> f1.toUri()
|
||||||
f2.toUri().toString().toLowerCase()));
|
.toString()
|
||||||
|
.toLowerCase()
|
||||||
|
.compareTo(
|
||||||
|
f2.toUri().toString().toLowerCase()));
|
||||||
for (Path file : imageFiles) {
|
for (Path file : imageFiles) {
|
||||||
IMG img = fileToIMGMap.get(file);
|
IMG img = fileToIMGMap.get(file);
|
||||||
if (img == null && !isExcludedImageFile(file)) {
|
if (img == null && !isExcludedImageFile(file)) {
|
||||||
|
@ -173,7 +176,10 @@ public class UnusedHelpImageFileFinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the help directory
|
// Create the help directory
|
||||||
helpCollections.add(HelpBuildUtils.toLocation(helpDirectoryFile));
|
HelpModuleLocation location = HelpBuildUtils.toLocation(helpDirectoryFile);
|
||||||
|
if (location != null) {
|
||||||
|
helpCollections.add(location);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return helpCollections;
|
return helpCollections;
|
||||||
|
|
|
@ -20,15 +20,16 @@ import java.net.*;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.help.HelpSet;
|
import javax.help.HelpSet;
|
||||||
import javax.help.Map.ID;
|
import javax.help.Map.ID;
|
||||||
import javax.help.TOCView;
|
import javax.help.TOCView;
|
||||||
import javax.swing.tree.DefaultMutableTreeNode;
|
import javax.swing.tree.DefaultMutableTreeNode;
|
||||||
|
|
||||||
|
import help.CustomTOCView.CustomTreeItemDecorator;
|
||||||
import help.HelpBuildUtils;
|
import help.HelpBuildUtils;
|
||||||
import help.TOCItemProvider;
|
import help.TOCItemProvider;
|
||||||
import help.CustomTOCView.CustomTreeItemDecorator;
|
|
||||||
import help.validator.model.*;
|
import help.validator.model.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,7 +99,10 @@ public class HelpModuleCollection implements TOCItemProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
private HelpModuleCollection(Collection<HelpModuleLocation> locations) {
|
private HelpModuleCollection(Collection<HelpModuleLocation> locations) {
|
||||||
helpLocations = new LinkedHashSet<>(locations);
|
|
||||||
|
helpLocations = locations.stream()
|
||||||
|
.filter(l -> l != null)
|
||||||
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||||
|
|
||||||
loadTOCs();
|
loadTOCs();
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.util.*;
|
||||||
import javax.help.HelpSet;
|
import javax.help.HelpSet;
|
||||||
|
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
|
import help.HelpBuildUtils;
|
||||||
import help.validator.model.*;
|
import help.validator.model.*;
|
||||||
|
|
||||||
public abstract class HelpModuleLocation {
|
public abstract class HelpModuleLocation {
|
||||||
|
@ -47,13 +48,16 @@ public abstract class HelpModuleLocation {
|
||||||
|
|
||||||
public abstract HelpSet loadHelpSet();
|
public abstract HelpSet loadHelpSet();
|
||||||
|
|
||||||
/** Returns true if this help location represents a source of input files to generate help output */
|
/**
|
||||||
|
* Returns true if this help location represents a source of input files to generate help output
|
||||||
|
* @return true if this help location represents a source of input files to generate help output
|
||||||
|
*/
|
||||||
public abstract boolean isHelpInputSource();
|
public abstract boolean isHelpInputSource();
|
||||||
|
|
||||||
protected void loadHelpTopics() {
|
protected void loadHelpTopics() {
|
||||||
Path helpTopicsDir = helpDir.resolve("topics");
|
Path helpTopicsDir = helpDir.resolve("topics");
|
||||||
if (!Files.exists(helpTopicsDir)) {
|
if (!Files.exists(helpTopicsDir)) {
|
||||||
throw new AssertException("No topics found in help dir: " + helpDir);
|
HelpBuildUtils.debug("No topics found in help dir: " + this);
|
||||||
}
|
}
|
||||||
|
|
||||||
try (DirectoryStream<Path> ds = Files.newDirectoryStream(helpTopicsDir);) {
|
try (DirectoryStream<Path> ds = Files.newDirectoryStream(helpTopicsDir);) {
|
||||||
|
@ -65,7 +69,7 @@ public abstract class HelpModuleLocation {
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
// I suppose there aren't any
|
// I suppose there aren't any
|
||||||
throw new AssertException("No topics found in help dir: " + helpDir);
|
throw new AssertException("No topics found in help dir: " + this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +197,7 @@ public abstract class HelpModuleLocation {
|
||||||
}
|
}
|
||||||
List<AnchorDefinition> list = map.get(name);
|
List<AnchorDefinition> list = map.get(name);
|
||||||
if (list == null) {
|
if (list == null) {
|
||||||
list = new ArrayList<AnchorDefinition>();
|
list = new ArrayList<>();
|
||||||
map.put(name, list);
|
map.put(name, list);
|
||||||
}
|
}
|
||||||
list.add(anchorDefinition);
|
list.add(anchorDefinition);
|
||||||
|
|
|
@ -21,7 +21,6 @@ import java.net.*;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import javax.help.HelpSet;
|
import javax.help.HelpSet;
|
||||||
import javax.help.HelpSetException;
|
import javax.help.HelpSetException;
|
||||||
|
@ -32,17 +31,29 @@ import help.validator.model.GhidraTOCFile;
|
||||||
|
|
||||||
public class JarHelpModuleLocation extends HelpModuleLocation {
|
public class JarHelpModuleLocation extends HelpModuleLocation {
|
||||||
|
|
||||||
/*
|
private static Map<String, String> env = new HashMap<>();
|
||||||
* format of 'helpDir':
|
|
||||||
* jar:file:///.../ghidra-prep/Ghidra/Features/Base/build/libs/Base.jar!/help
|
|
||||||
*/
|
|
||||||
private static final Pattern JAR_FILENAME_PATTERN = Pattern.compile(".*/(\\w*)\\.jar!/.*");
|
|
||||||
|
|
||||||
private static Map<String, String> env = new HashMap<String, String>();
|
|
||||||
static {
|
static {
|
||||||
env.put("create", "false");
|
env.put("create", "false");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static JarHelpModuleLocation fromFile(File jar) {
|
||||||
|
FileSystem fs = getOrCreateJarFS(jar);
|
||||||
|
Path helpRootPath = fs.getPath("/help");
|
||||||
|
if (!Files.exists(helpRootPath)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Path topicsPath = helpRootPath.resolve("topics");
|
||||||
|
|
||||||
|
if (!Files.exists(topicsPath)) {
|
||||||
|
// all help locations must have a topics directory; we can get here if the jar contains
|
||||||
|
// a package with the name 'help'
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new JarHelpModuleLocation(jar, helpRootPath);
|
||||||
|
}
|
||||||
|
|
||||||
private static FileSystem getOrCreateJarFS(File jar) {
|
private static FileSystem getOrCreateJarFS(File jar) {
|
||||||
URI jarURI;
|
URI jarURI;
|
||||||
try {
|
try {
|
||||||
|
@ -64,8 +75,8 @@ public class JarHelpModuleLocation extends HelpModuleLocation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public JarHelpModuleLocation(File file) {
|
private JarHelpModuleLocation(File jar, Path path) {
|
||||||
super(getOrCreateJarFS(file).getPath("/help"));
|
super(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -101,9 +112,11 @@ public class JarHelpModuleLocation extends HelpModuleLocation {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getModuleName(File jarFile) {
|
private String getModuleName(File jarFile) {
|
||||||
|
|
||||||
String name = jarFile.getName();
|
String name = jarFile.getName();
|
||||||
int dotIndex = name.indexOf('.');
|
int dotIndex = name.indexOf("-help.jar"); // dev mode
|
||||||
|
if (dotIndex == -1) {
|
||||||
|
dotIndex = name.indexOf(".jar"); // production mode
|
||||||
|
}
|
||||||
return name.substring(0, dotIndex);
|
return name.substring(0, dotIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,6 @@ package help.validator.location;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
import help.validator.location.HelpModuleLocation;
|
|
||||||
|
|
||||||
public abstract class HelpModuleLocationTestDouble extends HelpModuleLocation {
|
public abstract class HelpModuleLocationTestDouble extends HelpModuleLocation {
|
||||||
|
|
||||||
// this class exists to open up the package-level constructor
|
// this class exists to open up the package-level constructor
|
||||||
|
|
|
@ -42,14 +42,6 @@ file(ghidraDir + "/application.properties").withReader { reader ->
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
checkGradleVersion()
|
checkGradleVersion()
|
||||||
|
|
||||||
configurations {
|
|
||||||
helpPath
|
|
||||||
}
|
|
||||||
|
|
||||||
artifacts {
|
|
||||||
helpPath jar
|
|
||||||
}
|
|
||||||
|
|
||||||
task copyDependencies(type: Copy) {
|
task copyDependencies(type: Copy) {
|
||||||
from configurations.runtimeClasspath
|
from configurations.runtimeClasspath
|
||||||
into "lib"
|
into "lib"
|
||||||
|
@ -76,7 +68,6 @@ dependencies {
|
||||||
api fileTree(dir: ghidraDir + '/Features', include: "**/*.jar")
|
api fileTree(dir: ghidraDir + '/Features', include: "**/*.jar")
|
||||||
api fileTree(dir: ghidraDir + '/Debug', include: "**/*.jar")
|
api fileTree(dir: ghidraDir + '/Debug', include: "**/*.jar")
|
||||||
api fileTree(dir: ghidraDir + '/Processors', include: "**/*.jar")
|
api fileTree(dir: ghidraDir + '/Processors', include: "**/*.jar")
|
||||||
helpPath fileTree(dir: ghidraDir + '/Features/Base', include: "**/Base.jar")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def ZIP_NAME_PREFIX = "${DISTRO_PREFIX}_${RELEASE_NAME}_${getCurrentDate()}"
|
def ZIP_NAME_PREFIX = "${DISTRO_PREFIX}_${RELEASE_NAME}_${getCurrentDate()}"
|
||||||
|
@ -180,73 +171,211 @@ task buildExtension (type: Zip) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// task for calling the java help indexer
|
/*********************************************************************************
|
||||||
task indexHelp(type: JavaExec) {
|
* Help Build Code
|
||||||
File helpRootDir = file('src/main/help') // this the root dir for the help source
|
* Note: This code is derived from helpProject.gradle. Required changes should
|
||||||
File outputFile = file("build/help/main/help/${project.name}_JavaHelpSearch")
|
* be made to that file and then reapplied here.
|
||||||
onlyIf {helpRootDir.exists()}
|
*********************************************************************************/
|
||||||
|
|
||||||
dependsOn configurations.helpPath
|
sourceSets {
|
||||||
|
|
||||||
|
// register help resources to be considered inputs to this project; when these resources change,
|
||||||
|
// this project will be considered out-of-date
|
||||||
|
main {
|
||||||
|
resources {
|
||||||
|
srcDir 'src/main/help' // help .html files to be copied to the jar
|
||||||
|
srcDir 'build/help/main' // generated help items (from the indexer); copied to the jar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turns the given file into a 'normalized' path using the Java Path API
|
||||||
|
def normalize(File file) {
|
||||||
|
def path = null;
|
||||||
|
try {
|
||||||
|
path = java.nio.file.Paths.get(file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
catch (Exception e) { // InvalidPathException
|
||||||
|
// we have seen odd strings being placed into the classpath--ignore them
|
||||||
|
return cpPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
def normalizedPath = path.normalize();
|
||||||
|
def absolutePath = normalizedPath.toAbsolutePath();
|
||||||
|
return absolutePath.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the Ghidra module directory for the given file if it is a Ghidra jar file
|
||||||
|
def getModulePathFromJar(File file) {
|
||||||
|
|
||||||
|
String path = normalize(file)
|
||||||
|
String forwardSlashedPath = path.replaceAll("\\\\", "/")
|
||||||
|
def jarPattern = ~'.*/(.*)/(?:lib|build/libs)/(.+).jar'
|
||||||
|
def matcher = jarPattern.matcher(forwardSlashedPath)
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
def moduleName = matcher.group(1);
|
||||||
|
def index = forwardSlashedPath.indexOf(moduleName) + moduleName.length()
|
||||||
|
return forwardSlashedPath.substring(0, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method contains logic for calculating help inputs based on the classpath of the project
|
||||||
|
// The work is cached, as the inputs may be requested multiple times during a build
|
||||||
|
ext.helpInputsCache = null
|
||||||
|
def getHelpInputs(Collection fullClasspath) {
|
||||||
|
|
||||||
|
if (ext.helpInputsCache != null) {
|
||||||
|
return ext.helpInputsCache
|
||||||
|
}
|
||||||
|
|
||||||
|
def results = new HashSet<File>()
|
||||||
|
|
||||||
|
fullClasspath.each {
|
||||||
|
|
||||||
|
String moduleDirPath = getModulePathFromJar(it)
|
||||||
|
if (moduleDirPath == null) {
|
||||||
|
return // continue
|
||||||
|
}
|
||||||
|
|
||||||
|
getHelpInputsFromModule(moduleDirPath, results)
|
||||||
|
}
|
||||||
|
|
||||||
|
// the classpath above does not include my module's contents, so add that manually
|
||||||
|
def modulePath = file('.').getAbsolutePath()
|
||||||
|
getHelpInputsFromModule(modulePath, results)
|
||||||
|
|
||||||
|
ext.helpInputsCache = results.findAll(File::exists)
|
||||||
|
return ext.helpInputsCache
|
||||||
|
}
|
||||||
|
|
||||||
|
def getHelpInputsFromModule(String moduleDirPath, Set<File> results) {
|
||||||
|
|
||||||
|
// add all desired directories now and filter later those that do not exist
|
||||||
|
File moduleDir = new File(moduleDirPath)
|
||||||
|
results.add(new File(moduleDir, 'src/main/resources')) // images
|
||||||
|
results.add(new File(moduleDir, 'src/main/help')) // html files
|
||||||
|
|
||||||
|
File dataDir = new File(moduleDir, 'data') // theme properties files
|
||||||
|
if (dataDir.exists()) {
|
||||||
|
FileCollection themeFiles = fileTree(dataDir) {
|
||||||
|
include '**/*.theme.properties'
|
||||||
|
}
|
||||||
|
results.addAll(themeFiles.getFiles())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the given file is a jar file that contains a '/help/topics' diretory
|
||||||
|
def hasJarHelp(File file) {
|
||||||
|
|
||||||
|
if (!file.exists()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file.getAbsolutePath().endsWith(".jar")) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
def fileSystem = null;
|
||||||
|
try {
|
||||||
|
def jarURI = new URI("jar:file://" + file.toURI().getRawPath());
|
||||||
|
fileSystem = java.nio.file.FileSystems.getFileSystem(jarURI);
|
||||||
|
}
|
||||||
|
catch (Exception e) { // FileSystemNotFoundException
|
||||||
|
// handled below
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileSystem == null) {
|
||||||
|
// not yet created; try to create the file system
|
||||||
|
def jarURI = new URI("jar:file://" + file.toURI().getRawPath());
|
||||||
|
def env = Map.of("create", "false")
|
||||||
|
fileSystem = java.nio.file.FileSystems.newFileSystem(jarURI, env);
|
||||||
|
}
|
||||||
|
|
||||||
|
def topicsPath = fileSystem.getPath("/help/topics");
|
||||||
|
return java.nio.file.Files.exists(topicsPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register('cleanHelp') {
|
||||||
|
File helpOutput = file('build/help/main/help')
|
||||||
|
doFirst {
|
||||||
|
delete helpOutput
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Task for calling the java help indexer, which creates a searchable index of the help contents
|
||||||
|
tasks.register('indexHelp', JavaExec) {
|
||||||
|
|
||||||
|
File helpRootDir = file('src/main/help/help')
|
||||||
|
File outputFile = file("build/help/main/help/${project.name}_JavaHelpSearch")
|
||||||
|
|
||||||
inputs.dir helpRootDir
|
inputs.dir helpRootDir
|
||||||
outputs.dir outputFile
|
outputs.dir outputFile
|
||||||
|
|
||||||
classpath = sourceSets.main.runtimeClasspath // this modules runtime classpath (contains jhall.jar)
|
|
||||||
|
|
||||||
mainClass = 'com.sun.java.help.search.Indexer' // main class to call
|
classpath = sourceSets.main.runtimeClasspath
|
||||||
|
|
||||||
// tell the indexer where send its output
|
|
||||||
|
|
||||||
args '-db', outputFile.absolutePath
|
mainClass = 'com.sun.java.help.search.Indexer'
|
||||||
|
|
||||||
|
|
||||||
// The index has a config file parameter. The only thing we use in the config file
|
|
||||||
// is a root directory path that should be stripped off all the help references to
|
|
||||||
// make them relative instead of absolute
|
|
||||||
|
|
||||||
File configFile = file('build/helpconfig') // this is the config file that we will create
|
|
||||||
|
|
||||||
// create the config file when the task runs and not during configuration.
|
|
||||||
doFirst {
|
doFirst {
|
||||||
|
|
||||||
|
// gather up all the help files into a file collection
|
||||||
|
FileTree helpFiles = fileTree('src/main/help') {
|
||||||
|
include '**/*.htm'
|
||||||
|
include '**/*.html'
|
||||||
|
}
|
||||||
|
|
||||||
|
// The index has a config file parameter. The only thing we use in the config file
|
||||||
|
// is a root directory path that should be stripped off all the help references to
|
||||||
|
// make them relative instead of absolute
|
||||||
|
File configFile = file('build/helpconfig')
|
||||||
|
|
||||||
|
// create the config file when the task runs and not during configuration.
|
||||||
configFile.parentFile.mkdirs();
|
configFile.parentFile.mkdirs();
|
||||||
configFile.write "IndexRemove ${helpRootDir.absolutePath}" + File.separator + "\n"
|
configFile.write "IndexRemove ${helpRootDir.absolutePath}" + File.separator + "\n"
|
||||||
}
|
|
||||||
|
|
||||||
// pass the config file we created as an argument to the indexer
|
// pass the config file we created as an argument to the indexer
|
||||||
args '-c',"$configFile"
|
args '-c',"$configFile"
|
||||||
|
|
||||||
// gather up all the help files into a file collection
|
// tell the indexer where send its output
|
||||||
FileTree helpFiles = fileTree('src/main/help') {
|
args '-db', outputFile.absolutePath
|
||||||
include '**/*.htm'
|
|
||||||
include '**/*.html'
|
|
||||||
}
|
|
||||||
|
|
||||||
doFirst {
|
|
||||||
// for each help file that was found, add it as an argument to the indexer
|
// for each help file that was found, add it as an argument to the indexer
|
||||||
helpFiles.each { File file ->
|
helpFiles.each { File file ->
|
||||||
args "${file.absolutePath}"
|
args "${file.absolutePath}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
group "private"
|
|
||||||
description "indexes the helps files for this module. [gradle/helpProject.gradle]"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// task for building Ghidra help files - depends on the output from the help indexer
|
|
||||||
task buildHelp(type: JavaExec, dependsOn: indexHelp) {
|
|
||||||
|
|
||||||
File helpRootDir = file('src/main/help/help') // help root where topics dir lives
|
// Task for building Ghidra help files
|
||||||
File outputDir = file('build/help/main/help') // dir where we want the help files to be generated
|
// - depends on the output from the help indexer
|
||||||
onlyIf {helpRootDir.exists()}
|
// - validates help
|
||||||
|
// - the files generated will be placed in a diretory usable during development mode and will
|
||||||
|
// eventually be placed in the <Module>.jar file
|
||||||
|
tasks.register('buildHelp', JavaExec) {
|
||||||
|
|
||||||
|
group "private"
|
||||||
|
|
||||||
|
dependsOn 'indexHelp'
|
||||||
|
|
||||||
|
File helpRootDir = file('src/main/help/help')
|
||||||
|
File outputDir = file('build/help/main/help')
|
||||||
|
|
||||||
inputs.dir helpRootDir
|
inputs.dir helpRootDir
|
||||||
|
|
||||||
|
inputs.files({
|
||||||
|
// Note: this must be done lazily in a closure since the classpath is not ready at
|
||||||
|
// configuration time.
|
||||||
|
return getHelpInputs(sourceSets.main.runtimeClasspath.files)
|
||||||
|
})
|
||||||
|
|
||||||
outputs.dir outputDir
|
outputs.dir outputDir
|
||||||
|
|
||||||
classpath = sourceSets.main.runtimeClasspath // this modules runtime classpath (contains jhall.jar)
|
mainClass = 'help.GHelpBuilder'
|
||||||
|
|
||||||
mainClass = 'help.GHelpBuilder' // program to run to build help files.
|
|
||||||
|
|
||||||
args '-n', "${project.name}" // use the modules name as the base for the help file name
|
args '-n', "${project.name}" // use the module's name for the help file name
|
||||||
|
|
||||||
args '-o', "${outputDir.absolutePath}" // set the output directory arg
|
args '-o', "${outputDir.absolutePath}" // set the output directory arg
|
||||||
|
|
||||||
|
@ -254,21 +383,48 @@ task buildHelp(type: JavaExec, dependsOn: indexHelp) {
|
||||||
systemProperties = [
|
systemProperties = [
|
||||||
"ADDITIONAL_APPLICATION_ROOT_DIRS": "${ghidraInstallDir}/Ghidra"
|
"ADDITIONAL_APPLICATION_ROOT_DIRS": "${ghidraInstallDir}/Ghidra"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// args '-debug' // print debug info
|
||||||
|
|
||||||
doFirst {
|
doFirst {
|
||||||
configurations.helpPath.each {
|
|
||||||
|
//
|
||||||
|
// The classpath needs to include:
|
||||||
|
// 1) the jar of each dependent Module that has already been built
|
||||||
|
// 2) 'src/main/resources'
|
||||||
|
//
|
||||||
|
|
||||||
|
// Each java project and its dependencies are needed to locate each Ghidra module. Each
|
||||||
|
// module is scanned to find the theme properties files in the 'data' directories.
|
||||||
|
classpath += sourceSets.main.runtimeClasspath
|
||||||
|
|
||||||
|
classpath += files('src/main/resources')
|
||||||
|
|
||||||
|
// To build help, the validator needs any other help content that this module may reference.
|
||||||
|
// Add each of these dependencies as an argument to the validator.
|
||||||
|
def helpJars = classpath.findAll(file -> hasJarHelp(file))
|
||||||
|
helpJars.each {
|
||||||
args "-hp"
|
args "-hp"
|
||||||
args "${it.absolutePath}"
|
args "${it.absolutePath}"
|
||||||
}
|
}
|
||||||
args "${helpRootDir.absolutePath}" // tell the help builder what help dir to process
|
|
||||||
|
// The help dir to process. This needs to be the last argument to the process,
|
||||||
|
// thus, this is why it is inside of this block
|
||||||
|
args "${helpRootDir.absolutePath}"
|
||||||
|
|
||||||
|
// Sigal that any System.out messages from this Java process should be logged at INFO level.
|
||||||
|
// To see this output, run gradle with the '-i' option to show INFO messages.
|
||||||
|
logging.captureStandardOutput LogLevel.INFO
|
||||||
}
|
}
|
||||||
description " Builds the help for this module. [gradle/helpProject.gradle]\n"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// include the help into the module's jar
|
// include the help into the module's jar
|
||||||
jar {
|
jar {
|
||||||
|
duplicatesStrategy 'exclude'
|
||||||
from "build/help/main" // include the generated help index files
|
from "build/help/main" // include the generated help index files
|
||||||
from "src/main/help" // include the help source files
|
from "src/main/help" // include the help source files
|
||||||
archiveVersion = ""
|
archiveVersion = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,6 +432,10 @@ jar {
|
||||||
jar.dependsOn 'buildHelp'
|
jar.dependsOn 'buildHelp'
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************************************************************
|
||||||
|
* End Help Build Code
|
||||||
|
*********************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************************************
|
/*********************************************************************************
|
||||||
* Takes the given file and returns a string representing the file path with everything
|
* Takes the given file and returns a string representing the file path with everything
|
||||||
|
|
|
@ -18,54 +18,216 @@
|
||||||
have content for the Ghidra help system. A gradle project can include help support by adding
|
have content for the Ghidra help system. A gradle project can include help support by adding
|
||||||
the following to its build.gradle file.
|
the following to its build.gradle file.
|
||||||
|
|
||||||
apply from: "$rootProject.projectDir/gradle/helpProject.gradle"
|
apply from: "$rootProject.projectDir/gradle/helpProject.gradle"
|
||||||
|
|
||||||
Clients can register dependencies on other help modules by using the
|
|
||||||
'helpPath' configuration, like so:
|
|
||||||
|
|
||||||
helpPath project(path: ":Base", configuration: 'helpPath')
|
|
||||||
|
Note: This code is copied into buildExtension.gradle. All changes to this file should
|
||||||
|
be made to that file.
|
||||||
|
|
||||||
|
|
||||||
|
Help Build System Notes
|
||||||
|
This file contains custom glue coded needed to adapt the structure of Ghidra's help to the
|
||||||
|
Gradle build system. 'Building help' is defined as validating help content, generating
|
||||||
|
all necessary help files used by the Java Help system, and then placing the help and
|
||||||
|
generated content in a place to be consumed by Ghidra, which differs for development mode
|
||||||
|
and production mode. Validating the help content consists of ensuring: hyperlinks point
|
||||||
|
to valid destinations and image references point to existing images. (This is done to find
|
||||||
|
broken help links at build time.)
|
||||||
|
|
||||||
This example will put into the 'helpPath' configuration the project path of
|
|
||||||
'Base', using the value of it's 'helpPath' configuration. This brings us to the next
|
This file supports building help to work in development mode using
|
||||||
point--'helpPath' gets updated when the jar file is built to include the path of
|
Eclipse as well as when performing a build of Ghidra. Generated help content is written to:
|
||||||
the generated jar file. This allows future clients of a given help module to get
|
'build/help/main/help/'
|
||||||
the jar file path of that help module's output.
|
|
||||||
|
Developent Mode
|
||||||
|
The Eclipse projects are setup so that 'build/help/main' is part of the classpath. This
|
||||||
|
triggers Eclipse to copy help resources to the respective project's 'bin' directory,
|
||||||
|
which makes the help content available at runtime in Eclipse. In this setup no jar
|
||||||
|
files are used at runtime.
|
||||||
|
|
||||||
|
Production Mode
|
||||||
|
In production mode the contents of 'build/help/main' are added to the final output of
|
||||||
|
the Gradle 'jar' task, which will be <Module>.jar.
|
||||||
|
|
||||||
|
Gradle Building
|
||||||
|
During the help build process we place the contents of 'build/help/main' inside of an
|
||||||
|
artifact named <Module>-help.jar. This allows us to depend on these artifacts from the
|
||||||
|
projects we depend upon. Specifically, the 'buildHelpFiles' task depends upon the
|
||||||
|
<Module>-help.jar artifact from all dependent Modules.
|
||||||
|
|
||||||
|
To get Gradle's incremental building to work correctly, the following list of inputs
|
||||||
|
is declared for validating and building the help content:
|
||||||
|
1) Java files in the Help module used to build help - the help building code
|
||||||
|
2) all dependency data/*.theme.properties - for images used by help via theme IDs
|
||||||
|
3) all dependency src/main/help folder - for help content
|
||||||
|
4) all dependency src/main/resources - for images used by help
|
||||||
|
5) This module's equivalent inputs for 2-3
|
||||||
|
|
||||||
|
In order to correctly find these inputs, we use the main runtime classpath to find
|
||||||
|
Ghidra Modules. These modules are then scanned to find these inputs for each module.
|
||||||
|
The final collection of all these items for all dependent Modules is added to the set
|
||||||
|
of task inputs for building help. Thus, when any of the input above change, the help is
|
||||||
|
considered out-of-date and will be rebuilt.
|
||||||
|
|
||||||
|
The help build code is called via a JavaExec call. This call will pass arguments to the
|
||||||
|
process for any dependent Module's help. This dependent help will be inside of the
|
||||||
|
<Module>-help.jar artifact described above. This file contains code to locate those
|
||||||
|
artifacts so they can be passed into the help build java process.
|
||||||
|
|
||||||
*****************************************************************************************/
|
*****************************************************************************************/
|
||||||
|
|
||||||
// The help modules must be configured first so that we can reference its runtime classpath
|
// The help modules must be configured first so that we can reference its runtime classpath
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
// The Help Build System takes optional paths to resolve dependencies. Build files
|
|
||||||
// that use this 'script plugin' may put project paths into this variable.
|
|
||||||
helpPath
|
|
||||||
}
|
|
||||||
|
|
||||||
artifacts {
|
// This represents the Help module jar file. This is required for building help.
|
||||||
// The helpPath is updated to include the jar file output of the help build.
|
helpModule
|
||||||
helpPath jar
|
|
||||||
}
|
// This is used by the indexHelp task to configure the jar file dependency
|
||||||
|
helpIndex
|
||||||
sourceSets {
|
|
||||||
helpIndex {
|
|
||||||
java {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
main {
|
|
||||||
resources {
|
|
||||||
srcDir 'src/main/help'
|
|
||||||
srcDir 'build/help/main'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
helpIndexImplementation "javax.help:javahelp:2.0.05"
|
|
||||||
helpIndexImplementation project(':Help')
|
helpIndex "javax.help:javahelp:2.0.05"
|
||||||
|
|
||||||
|
// signal that we depend on the Help.jar for our Java build files
|
||||||
|
helpModule project(':Help')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Task for calling the java help indexer, which creates a searchable index of the
|
sourceSets {
|
||||||
// help contents.
|
|
||||||
task indexHelp(type: JavaExec) {
|
// register help resources to be considered inputs to this project; when these resources change,
|
||||||
|
// this project will be considered out-of-date
|
||||||
|
main {
|
||||||
|
resources {
|
||||||
|
srcDir 'src/main/help' // help .html files to be copied to the jar
|
||||||
|
srcDir 'build/help/main' // generated help items (from the indexer); copied to the jar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************************
|
||||||
|
Utility Methods
|
||||||
|
*****************************************************************************************/
|
||||||
|
|
||||||
|
// Turns the given file into a 'normalized' path using the Java Path API
|
||||||
|
def normalize(File file) {
|
||||||
|
def path = null;
|
||||||
|
try {
|
||||||
|
path = java.nio.file.Paths.get(file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
catch (Exception e) { // InvalidPathException
|
||||||
|
// we have seen odd strings being placed into the classpath--ignore them
|
||||||
|
return cpPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
def normalizedPath = path.normalize();
|
||||||
|
def absolutePath = normalizedPath.toAbsolutePath();
|
||||||
|
return absolutePath.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the Ghidra module directory for the given file if it is a Ghidra jar file
|
||||||
|
def getModulePathFromJar(File file) {
|
||||||
|
|
||||||
|
String path = normalize(file)
|
||||||
|
String forwardSlashedPath = path.replaceAll("\\\\", "/")
|
||||||
|
def jarPattern = ~'.*/(.*)/(?:lib|build/libs)/(.+).jar'
|
||||||
|
def matcher = jarPattern.matcher(forwardSlashedPath)
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
def moduleName = matcher.group(1);
|
||||||
|
def index = forwardSlashedPath.indexOf(moduleName) + moduleName.length()
|
||||||
|
return forwardSlashedPath.substring(0, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parses the classpath looking for all Module jar file paths, using those to locate the module
|
||||||
|
// that contains that jar file.
|
||||||
|
// Note: In development mode, the <Module>.jar file on the classpath may not actually yet be built.
|
||||||
|
// In that case, we can still use that path to locate the module.
|
||||||
|
def getMyModules(Collection<File> fullClasspath) {
|
||||||
|
return fullClasspath.collect(file -> getModulePathFromJar(file))
|
||||||
|
.findAll(path -> path != null)
|
||||||
|
.collect(path -> new File(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method contains logic for calculating help inputs based on the classpath of the project
|
||||||
|
// The work is cached, as the inputs may be requested multiple times during a build
|
||||||
|
ext.helpInputsCache = null
|
||||||
|
def getHelpInputs(Collection<File> fullClasspath) {
|
||||||
|
|
||||||
|
if (ext.helpInputsCache != null) {
|
||||||
|
return ext.helpInputsCache
|
||||||
|
}
|
||||||
|
|
||||||
|
def results = new HashSet<File>()
|
||||||
|
Collection<File> modules = getMyModules(fullClasspath)
|
||||||
|
modules.each { m ->
|
||||||
|
getHelpInputsFromModule(m.getAbsolutePath(), results)
|
||||||
|
}
|
||||||
|
|
||||||
|
// the classpath above does not include my module's contents, so add that manually
|
||||||
|
def modulePath = file('.').getAbsolutePath()
|
||||||
|
getHelpInputsFromModule(modulePath, results)
|
||||||
|
|
||||||
|
ext.helpInputsCache = results.findAll(File::exists)
|
||||||
|
return ext.helpInputsCache
|
||||||
|
}
|
||||||
|
|
||||||
|
def getHelpInputsFromModule(String moduleDirPath, Set<File> results) {
|
||||||
|
|
||||||
|
// add all desired directories now and filter later those that do not exist
|
||||||
|
File moduleDir = new File(moduleDirPath)
|
||||||
|
results.add(new File(moduleDir, 'src/main/resources')) // images
|
||||||
|
results.add(new File(moduleDir, 'src/main/help')) // html files
|
||||||
|
|
||||||
|
File dataDir = new File(moduleDir, 'data') // theme properties files
|
||||||
|
if (dataDir.exists()) {
|
||||||
|
FileCollection themeFiles = fileTree(dataDir) {
|
||||||
|
include '**/*.theme.properties'
|
||||||
|
}
|
||||||
|
results.addAll(themeFiles.getFiles())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def getModuleResourcesDirs(Collection<File> fullClasspath) {
|
||||||
|
def modules = getMyModules(fullClasspath)
|
||||||
|
return modules.collect(m -> new File(m, 'src/main/resources'))
|
||||||
|
.findAll(dir -> dir.exists())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locatates 'buildHelp' tasks in projects that this project depends on. The output of the tasks
|
||||||
|
// is the module's help jar, which is only used to build help and not in the final release. The
|
||||||
|
// jar file names follow this format: <Module>-help.jar.
|
||||||
|
def getDependentProjectHelpTasks(Collection<File> fullClasspath) {
|
||||||
|
|
||||||
|
def myModules = getMyModules(fullClasspath)
|
||||||
|
def myProjects = filterProjectsBy(myModules)
|
||||||
|
return myProjects.collect(p -> p.tasks.findByPath('buildHelp'))
|
||||||
|
.findAll(t -> t != null)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only projects matching the given collection of modules are returned
|
||||||
|
def filterProjectsBy(Collection<File> modules) {
|
||||||
|
return modules.collect(m -> m.getName())
|
||||||
|
.collect(name -> rootProject.findProject(name))
|
||||||
|
.findAll(p -> p != null)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************************
|
||||||
|
Tasks
|
||||||
|
*****************************************************************************************/
|
||||||
|
|
||||||
|
tasks.register('cleanHelp') {
|
||||||
|
File helpOutput = file('build/help/main/help')
|
||||||
|
doFirst {
|
||||||
|
delete helpOutput
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Task for calling the java help indexer, which creates a searchable index of the help contents
|
||||||
|
tasks.register('indexHelp', JavaExec) {
|
||||||
|
|
||||||
group "private"
|
group "private"
|
||||||
description "indexes the helps files for this module. [gradle/helpProject.gradle]"
|
description "indexes the helps files for this module. [gradle/helpProject.gradle]"
|
||||||
|
@ -73,44 +235,42 @@ task indexHelp(type: JavaExec) {
|
||||||
File helpRootDir = file('src/main/help/help')
|
File helpRootDir = file('src/main/help/help')
|
||||||
File outputFile = file("build/help/main/help/${project.name}_JavaHelpSearch")
|
File outputFile = file("build/help/main/help/${project.name}_JavaHelpSearch")
|
||||||
|
|
||||||
dependsOn configurations.helpPath
|
|
||||||
dependsOn configurations.runtimeClasspath
|
|
||||||
|
|
||||||
inputs.dir helpRootDir
|
inputs.dir helpRootDir
|
||||||
outputs.dir outputFile
|
outputs.dir outputFile
|
||||||
|
|
||||||
classpath = sourceSets.helpIndex.runtimeClasspath
|
classpath = configurations.helpIndex
|
||||||
|
|
||||||
mainClass = 'com.sun.java.help.search.Indexer'
|
mainClass = 'com.sun.java.help.search.Indexer'
|
||||||
|
|
||||||
// tell the indexer where send its output
|
|
||||||
args '-db', outputFile.absolutePath
|
|
||||||
|
|
||||||
// The index has a config file parameter. The only thing we use in the config file
|
|
||||||
// is a root directory path that should be stripped off all the help references to
|
|
||||||
// make them relative instead of absolute
|
|
||||||
File configFile = file('build/helpconfig')
|
|
||||||
|
|
||||||
// gather up all the help files into a file collection
|
|
||||||
FileTree helpFiles = fileTree('src/main/help') {
|
|
||||||
include '**/*.htm'
|
|
||||||
include '**/*.html'
|
|
||||||
}
|
|
||||||
|
|
||||||
// pass the config file we created as an argument to the indexer
|
|
||||||
args '-c',"$configFile"
|
|
||||||
|
|
||||||
|
|
||||||
doFirst {
|
doFirst {
|
||||||
|
|
||||||
|
// gather up all the help files into a file collection
|
||||||
|
FileTree helpFiles = fileTree('src/main/help') {
|
||||||
|
include '**/*.htm'
|
||||||
|
include '**/*.html'
|
||||||
|
}
|
||||||
|
|
||||||
if (helpFiles.isEmpty()) {
|
if (helpFiles.isEmpty()) {
|
||||||
// must have help to index
|
// must have help to index
|
||||||
throw new GradleException("No help files found")
|
throw new GradleException("No help files found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The index tool has a config file parameter, which allows you to pass arguments via a file
|
||||||
|
// instead of the command line. This is useful when dealing with file paths. The only
|
||||||
|
// thing we use in the config file is a root directory path that should be stripped off all
|
||||||
|
// the help references to make them relative instead of absolute. We generate this config
|
||||||
|
// file below.
|
||||||
|
File configFile = file('build/helpconfig')
|
||||||
|
|
||||||
// create the config file when the task runs and not during configuration.
|
// create the config file when the task runs and not during configuration.
|
||||||
configFile.parentFile.mkdirs();
|
configFile.parentFile.mkdirs();
|
||||||
configFile.write "IndexRemove ${helpRootDir.absolutePath}" + File.separator + "\n"
|
configFile.write "IndexRemove ${helpRootDir.absolutePath}" + File.separator + "\n"
|
||||||
|
|
||||||
|
// pass the config file we created as an argument to the indexer
|
||||||
|
args '-c',"$configFile"
|
||||||
|
|
||||||
|
// tell the indexer where send its output
|
||||||
|
args '-db', outputFile.absolutePath
|
||||||
|
|
||||||
// for each help file that was found, add it as an argument to the indexer
|
// for each help file that was found, add it as an argument to the indexer
|
||||||
helpFiles.each { File file ->
|
helpFiles.each { File file ->
|
||||||
|
@ -119,31 +279,49 @@ task indexHelp(type: JavaExec) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task cleanHelp {
|
|
||||||
File helpOutput = file('build/help/main/help')
|
|
||||||
doFirst {
|
|
||||||
delete helpOutput
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Task for building Ghidra help files
|
// Task for building Ghidra help files
|
||||||
// - depends on the output from the help indexer
|
// - depends on the output from the help indexer
|
||||||
task buildHelp(type: JavaExec, dependsOn: indexHelp) {
|
// - validates help
|
||||||
group rootProject.GHIDRA_GROUP
|
// - the files generated will be placed in a diretory usable during development mode and will
|
||||||
description " Builds the help for this module. [gradle/helpProject.gradle]\n"
|
// eventually be placed in:
|
||||||
|
// - the <Module>.jar file in production mode, or
|
||||||
|
// - the <Module>-help.jar file in development mode
|
||||||
|
tasks.register('buildHelpFiles', JavaExec) {
|
||||||
|
|
||||||
outputs.upToDateWhen {false} // TODO remove this. we should be able to get the inputs right
|
group "private"
|
||||||
// the issue is if docs get changed in a dependant module,
|
|
||||||
// this modules needs to know to rebuild
|
dependsOn 'indexHelp'
|
||||||
|
|
||||||
|
// Depend on all <Module>-help.jar files for our dependency modules. These jar files must be
|
||||||
|
// built before we run, since the files will be passed to the help builder. Use a closure to
|
||||||
|
// ensure that the classpath is ready when needed.
|
||||||
|
dependsOn({
|
||||||
|
getDependentProjectHelpTasks(sourceSets.main.runtimeClasspath.files)
|
||||||
|
})
|
||||||
|
|
||||||
File helpRootDir = file('src/main/help/help')
|
File helpRootDir = file('src/main/help/help')
|
||||||
File outputDir = file('build/help/main/help')
|
File outputDir = file('build/help/main/help')
|
||||||
|
|
||||||
inputs.dir file('src/main/help');
|
//
|
||||||
File resourcesDir = file('src/main/resources')
|
// Inputs (used for incremental building):
|
||||||
if (resourcesDir.exists()) {
|
// 1) Java files in the Help module used to build help
|
||||||
inputs.dir resourcesDir
|
// 2) all dependency data/**/*.theme.properties - for images used by help via theme IDs
|
||||||
}
|
// 3) all dependency src/main/help folder - for help content
|
||||||
|
// 4) all dependency src/main/resources - for images used by help
|
||||||
|
// 5) This module's equivalent inputs for 2-3
|
||||||
|
//
|
||||||
|
|
||||||
|
// 1) Java files in the Help module used to build help
|
||||||
|
inputs.files(configurations.helpModule)
|
||||||
|
|
||||||
|
// 2-5) from above
|
||||||
|
inputs.files({
|
||||||
|
// Note: this must be done lazily in a closure since the classpath is not ready at
|
||||||
|
// configuration time.
|
||||||
|
return getHelpInputs(sourceSets.main.runtimeClasspath.files)
|
||||||
|
})
|
||||||
|
|
||||||
outputs.dir outputDir
|
outputs.dir outputDir
|
||||||
|
|
||||||
mainClass = 'help.GHelpBuilder'
|
mainClass = 'help.GHelpBuilder'
|
||||||
|
@ -157,52 +335,93 @@ task buildHelp(type: JavaExec, dependsOn: indexHelp) {
|
||||||
|
|
||||||
doFirst {
|
doFirst {
|
||||||
|
|
||||||
// this module's runtime classpath (contains jhall.jar)
|
//
|
||||||
classpath project(':Help').sourceSets.main.runtimeClasspath
|
// The classpath needs to include items used by internal Java code to validate help
|
||||||
|
// resources:
|
||||||
// include the classpath for the project using this Help gradle script plugin
|
// 1) The jar path of each dependent Module. The jar file will be on the 'main' runtime
|
||||||
classpath += project.sourceSets.main.runtimeClasspath
|
// classpath, but may not yet exist. Regardless, the Java code will use the path to
|
||||||
// since this runs BEFORE resources are copied, include the resources source dir in
|
// locate the module for that path.
|
||||||
// the classpath so the help validator can find them
|
// 2) Each module's 'src/main/resources' dir (this is needed when the jar files from 1
|
||||||
classpath += files('src/main/resources')
|
// above have not been built)
|
||||||
|
// 3) This module's 'src/main/resources' dir
|
||||||
|
//
|
||||||
|
|
||||||
configurations.helpPath.each {
|
// Each java project and its dependencies are needed to locate each Ghidra module. Each
|
||||||
args "-hp"
|
// module is scanned to find the theme properties files in the 'data' directories.
|
||||||
args "${it.absolutePath}"
|
classpath += sourceSets.main.runtimeClasspath
|
||||||
}
|
|
||||||
|
classpath += files(getModuleResourcesDirs(sourceSets.main.runtimeClasspath.files))
|
||||||
|
|
||||||
|
classpath += files('src/main/resources')
|
||||||
|
|
||||||
|
|
||||||
|
// To build help, the validator needs any other help content that this module may reference.
|
||||||
|
// Add each of these dependencies as an argument to the validator.
|
||||||
|
// The dependency file is the <Module>-help.jar file from the 'buildHelp' tasks upon which
|
||||||
|
// we depend.
|
||||||
|
def buildHelpTasks = getDependentProjectHelpTasks(sourceSets.main.runtimeClasspath.files)
|
||||||
|
buildHelpTasks.each {
|
||||||
|
|
||||||
|
def jarFiles = it.outputs.files
|
||||||
|
jarFiles.each { helpJar ->
|
||||||
|
args "-hp"
|
||||||
|
args "${helpJar.absolutePath}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The help dir to process. This needs to be the last argument to the process,
|
// The help dir to process. This needs to be the last argument to the process,
|
||||||
// thus, this is why it is inside of this block
|
// thus, this is why it is inside of this block
|
||||||
args "${helpRootDir.absolutePath}"
|
args "${helpRootDir.absolutePath}"
|
||||||
|
|
||||||
|
// Sigal that any System.out messages from this Java process should be logged at INFO level.
|
||||||
|
// To see this output, run gradle with the '-i' option to show INFO messages.
|
||||||
|
logging.captureStandardOutput LogLevel.INFO
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This task creates a jar file that is used by dependent modules only at build time. The name of
|
||||||
|
* this jar is <Module>-help.jar. This is in contrast to each module's jar which itself contains
|
||||||
|
* all help needed in production. The module's jar filename is <Module>.jar.
|
||||||
|
*/
|
||||||
|
tasks.register('buildHelp', Jar) {
|
||||||
|
|
||||||
|
group rootProject.GHIDRA_GROUP
|
||||||
|
description " Builds the help for this module. [gradle/helpProject.gradle]\n"
|
||||||
|
|
||||||
|
dependsOn tasks.named('buildHelpFiles')
|
||||||
|
duplicatesStrategy 'exclude'
|
||||||
|
|
||||||
|
from "build/help/main" // include the generated help and index files from
|
||||||
|
from "src/main/help" // include the help source files
|
||||||
|
|
||||||
|
destinationDirectory = file("build/libs")
|
||||||
|
archiveBaseName = project.name + '-help'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Task for finding unused images that are not referenced from Ghidra help files
|
// Task for finding unused images that are not referenced from Ghidra help files
|
||||||
task findUnusedHelp(type: JavaExec) {
|
tasks.register('findUnusedHelp', JavaExec) {
|
||||||
group rootProject.GHIDRA_GROUP
|
|
||||||
|
group "private"
|
||||||
description " Finds unused help images for this module. [gradle/helpProject.gradle]\n"
|
description " Finds unused help images for this module. [gradle/helpProject.gradle]\n"
|
||||||
|
|
||||||
File helpRootDir = file('src/main/help/help')
|
File helpRootDir = file('src/main/help/help')
|
||||||
File outputDir = file('build/help/main/help')
|
|
||||||
|
|
||||||
dependsOn configurations.helpPath
|
|
||||||
|
|
||||||
inputs.dir helpRootDir
|
inputs.dir helpRootDir
|
||||||
|
inputs.files(configurations.helpModule)
|
||||||
|
|
||||||
mainClass = 'help.validator.UnusedHelpImageFileFinder'
|
mainClass = 'help.validator.UnusedHelpImageFileFinder'
|
||||||
|
|
||||||
// args '-debug' // print debug info
|
// args '-debug' // print debug info
|
||||||
|
|
||||||
doFirst {
|
doFirst {
|
||||||
classpath project(':Help').sourceSets.main.runtimeClasspath
|
classpath sourceSets.main.runtimeClasspath
|
||||||
|
|
||||||
// the current help dir to process
|
// the current help dir to process
|
||||||
args "-hp"
|
args "-hp"
|
||||||
args "${helpRootDir.absolutePath}"
|
args "${helpRootDir.absolutePath}"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -210,7 +429,7 @@ task findUnusedHelp(type: JavaExec) {
|
||||||
// include the help into the module's jar
|
// include the help into the module's jar
|
||||||
jar {
|
jar {
|
||||||
duplicatesStrategy 'exclude'
|
duplicatesStrategy 'exclude'
|
||||||
from "build/help/main" // include the generated help index files
|
from "build/help/main" // include the generated help and index files
|
||||||
from "src/main/help" // include the help source files
|
from "src/main/help" // include the help source files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,3 +441,4 @@ jar.dependsOn buildHelp
|
||||||
// make sure generated help directories exist during prepdev so that the directories are created and
|
// make sure generated help directories exist during prepdev so that the directories are created and
|
||||||
// eclipse doesn't complain about missing src directories.
|
// eclipse doesn't complain about missing src directories.
|
||||||
rootProject.prepDev.dependsOn buildHelp
|
rootProject.prepDev.dependsOn buildHelp
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user