refactor: update CLI commands and remove deprecated quick analysis feature

This commit is contained in:
Alexander Kiselev
2026-02-04 19:36:16 -08:00
parent 9ce351575b
commit 8aadc35e0d
9 changed files with 186 additions and 308 deletions
+40 -79
View File
@@ -105,9 +105,6 @@ pub enum Commands {
/// Set default values
SetDefault(SetDefaultArgs),
/// Quick analysis (import + analyze + summary)
Quick(QuickArgs),
/// Program summary
Summary(SummaryArgs),
@@ -129,9 +126,46 @@ pub enum Commands {
/// Analyze a program
Analyze(AnalyzeArgs),
/// Daemon management commands
#[command(subcommand)]
Daemon(DaemonCommands),
/// Start the bridge
Start {
/// Project path
#[arg(long)]
project: Option<String>,
/// Program name to load
#[arg(long)]
program: Option<String>,
},
/// Stop the bridge
Stop {
/// Project path
#[arg(long)]
project: Option<String>,
},
/// Restart the bridge
Restart {
/// Project path
#[arg(long)]
project: Option<String>,
/// Program name to load
#[arg(long)]
program: Option<String>,
},
/// Show bridge status
Status {
/// Project path
#[arg(long)]
project: Option<String>,
},
/// Ping the bridge
Ping {
/// Project path
#[arg(long)]
project: Option<String>,
},
/// Download and setup Ghidra automatically
Setup(SetupArgs),
@@ -683,13 +717,6 @@ pub struct SetDefaultArgs {
pub value: String,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct QuickArgs {
pub binary: String,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct SummaryArgs {
#[command(flatten)]
@@ -759,72 +786,6 @@ pub struct QueryOptions {
pub json: bool,
}
/// Daemon management commands
#[derive(Subcommand, Clone, Serialize, Deserialize, Debug)]
pub enum DaemonCommands {
/// Start the daemon
Start {
/// Project path
#[arg(long)]
project: Option<String>,
/// Program name to load
#[arg(long)]
program: Option<String>,
/// Port to listen on (default: auto-select)
#[arg(long)]
port: Option<u16>,
/// Run in foreground (don't daemonize)
#[arg(long)]
foreground: bool,
},
/// Stop the daemon
Stop {
/// Project path
#[arg(long)]
project: Option<String>,
},
/// Restart the daemon
Restart {
/// Project path
#[arg(long)]
project: Option<String>,
/// Program name to load
#[arg(long)]
program: Option<String>,
/// Port to listen on (default: auto-select)
#[arg(long)]
port: Option<u16>,
},
/// Get daemon status
Status {
/// Project path
#[arg(long)]
project: Option<String>,
},
/// Ping the daemon
Ping {
/// Project path
#[arg(long)]
project: Option<String>,
},
/// Clear the cache
ClearCache {
/// Project path
#[arg(long)]
project: Option<String>,
},
}
/// Arguments for the setup command
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct SetupArgs {
+5
View File
@@ -21,6 +21,8 @@ pub enum BridgeStartMode {
Import { binary_path: String },
/// Open an existing program in the project
Process { program_name: String },
/// Open the project without loading a specific program
Project,
}
/// Embedded Java bridge script
@@ -208,6 +210,9 @@ pub fn start_bridge(
BridgeStartMode::Process { program_name } => {
cmd.arg("-process").arg(program_name).arg("-noanalysis");
}
BridgeStartMode::Project => {
cmd.arg("-process").arg("-noanalysis");
}
}
// Add Java bridge script args
+77 -36
View File
@@ -53,9 +53,11 @@ import java.util.Iterator;
public class GhidraCliBridge extends GhidraScript {
private Gson gson = new GsonBuilder().serializeNulls().create();
private long startTime;
@Override
public void run() throws Exception {
startTime = System.currentTimeMillis();
// Get port file path from script arguments
String[] scriptArgs = getScriptArgs();
if (scriptArgs.length < 1) {
@@ -239,6 +241,8 @@ public class GhidraCliBridge extends GhidraScript {
case "script_list": return handleScriptList();
// Batch
case "batch": return handleBatch(args);
// Bridge info
case "bridge_info": return handleBridgeInfo();
default: return null;
}
}
@@ -316,6 +320,28 @@ public class GhidraCliBridge extends GhidraScript {
return result;
}
private JsonObject handleBridgeInfo() {
JsonObject result = new JsonObject();
result.addProperty("has_current_program", currentProgram != null);
if (currentProgram != null) {
result.addProperty("current_program", currentProgram.getName());
}
result.addProperty("uptime_ms", System.currentTimeMillis() - startTime);
Project project = state.getProject();
if (project != null) {
result.addProperty("project_name", project.getName());
try {
ProjectData projectData = project.getProjectData();
DomainFolder rootFolder = projectData.getRootFolder();
result.addProperty("program_count", rootFolder.getFiles().length);
} catch (Exception e) {
result.addProperty("program_count", 0);
}
}
return result;
}
private JsonObject handleProgramInfo() {
if (currentProgram == null) {
return errorResult("No program loaded");
@@ -596,8 +622,7 @@ public class GhidraCliBridge extends GhidraScript {
ReferenceManager refMgr = currentProgram.getReferenceManager();
FunctionManager fm = currentProgram.getFunctionManager();
Reference[] refs = refMgr.getReferencesTo(addr);
for (Reference ref : refs) {
for (Reference ref : refMgr.getReferencesTo(addr)) {
Address fromAddr = ref.getFromAddress();
Function fromFunc = fm.getFunctionContaining(fromAddr);
Function toFunc = fm.getFunctionContaining(addr);
@@ -740,7 +765,10 @@ public class GhidraCliBridge extends GhidraScript {
private JsonObject handleAnalyze(JsonObject args) {
String programName = getArgString(args, "program");
if (programName == null || programName.isEmpty()) {
return errorResult("No program name provided");
if (currentProgram == null) {
return errorResult("No program loaded. Use 'open_program' or 'import' first.");
}
programName = currentProgram.getName();
}
if (currentProgram == null) {
@@ -758,35 +786,10 @@ public class GhidraCliBridge extends GhidraScript {
}
try {
// Try Ghidra 12+ import path first, fall back to older path
Class<?> aamClass;
try {
aamClass = Class.forName("ghidra.app.plugin.core.analysis.AutoAnalysisManager");
} catch (ClassNotFoundException e) {
aamClass = Class.forName("ghidra.app.cmd.analysis.AutoAnalysisManager");
}
java.lang.reflect.Method getManager = aamClass.getMethod("getAnalysisManager", ghidra.program.model.listing.Program.class);
Object autoMgr = getManager.invoke(null, currentProgram);
if (autoMgr == null) {
return errorResult("Could not get AutoAnalysisManager");
}
TaskMonitor mon = new ConsoleTaskMonitor();
// Schedule full re-analysis
java.lang.reflect.Method reAnalyze = aamClass.getMethod("reAnalyzeAll", Address.class);
reAnalyze.invoke(autoMgr, (Address) null);
java.lang.reflect.Method startAnalysis = aamClass.getMethod("startAnalysis", TaskMonitor.class);
startAnalysis.invoke(autoMgr, mon);
// Poll until analysis completes
java.lang.reflect.Method isAnalyzing = aamClass.getMethod("isAnalyzing");
while ((Boolean) isAnalyzing.invoke(autoMgr)) {
Thread.sleep(1000);
}
// Use GhidraScript's built-in analyzeAll which works across Ghidra versions
analyzeAll(currentProgram);
// Save the program
try {
@@ -795,9 +798,11 @@ public class GhidraCliBridge extends GhidraScript {
// Best effort
}
FunctionManager fm = currentProgram.getFunctionManager();
JsonObject result = new JsonObject();
result.addProperty("status", "success");
result.addProperty("program", programName);
result.addProperty("function_count", fm.getFunctionCount());
return result;
} catch (Exception e) {
@@ -826,12 +831,48 @@ public class GhidraCliBridge extends GhidraScript {
prog.addProperty("type", domainFile.getContentType());
prog.addProperty("version", domainFile.getVersion());
prog.addProperty("current", isCurrent);
// Add analysis metadata
if (isCurrent && currentProgram != null) {
// For current program, use live data
FunctionManager fm = currentProgram.getFunctionManager();
int funcCount = fm.getFunctionCount();
prog.addProperty("function_count", funcCount);
prog.addProperty("analyzed", funcCount > 1);
prog.addProperty("executable_format", currentProgram.getExecutableFormat());
} else {
// For other programs, use DomainFile metadata
try {
java.util.Map<String, String> metadata = domainFile.getMetadata();
if (metadata != null) {
String funcCountStr = metadata.get("# of Functions");
int funcCount = 0;
if (funcCountStr != null) {
try { funcCount = Integer.parseInt(funcCountStr.trim()); }
catch (NumberFormatException ignored) {}
}
prog.addProperty("function_count", funcCount);
prog.addProperty("analyzed", funcCount > 1);
String exeFmt = metadata.get("Executable Format");
if (exeFmt != null) {
prog.addProperty("executable_format", exeFmt);
}
}
} catch (Exception ignored) {
// metadata not available for this file
}
}
programs.add(prog);
}
JsonObject result = new JsonObject();
result.add("programs", programs);
result.addProperty("count", programs.size());
result.addProperty("has_current_program", currentProgram != null);
if (currentProgram != null) {
result.addProperty("current_program_name", currentProgram.getName());
}
return result;
} catch (Exception e) {
@@ -1178,10 +1219,9 @@ public class GhidraCliBridge extends GhidraScript {
ReferenceManager refMgr = currentProgram.getReferenceManager();
Address targetAddr = targetFunc.getEntryPoint();
Reference[] refs = refMgr.getReferencesTo(targetAddr);
JsonArray results = new JsonArray();
for (Reference ref : refs) {
for (Reference ref : refMgr.getReferencesTo(targetAddr)) {
if (ref.getReferenceType().isCall()) {
Address fromAddr = ref.getFromAddress();
Function callerFunc = fm.getFunctionContaining(fromAddr);
@@ -1262,8 +1302,10 @@ public class GhidraCliBridge extends GhidraScript {
Address funcAddr = func.getEntryPoint();
long funcSize = func.getBody().getNumAddresses();
Reference[] refs = refMgr.getReferencesTo(funcAddr);
int xrefCount = refs.length;
int xrefCount = 0;
for (Reference ref : refMgr.getReferencesTo(funcAddr)) {
xrefCount++;
}
JsonArray reasons = new JsonArray();
@@ -1953,8 +1995,7 @@ public class GhidraCliBridge extends GhidraScript {
if (visited.contains(funcAddrStr)) return;
visited.add(funcAddrStr);
Reference[] refs = refMgr.getReferencesTo(func.getEntryPoint());
for (Reference ref : refs) {
for (Reference ref : refMgr.getReferencesTo(func.getEntryPoint())) {
if (ref.getReferenceType().isCall()) {
Address fromAddr = ref.getFromAddress();
Function callerFunc = fm.getFunctionContaining(fromAddr);
+5
View File
@@ -94,6 +94,11 @@ impl BridgeClient {
self.send_command("status", None)
}
/// Get bridge info (current program, project name, program count, uptime).
pub fn bridge_info(&self) -> Result<serde_json::Value> {
self.send_command("bridge_info", None)
}
/// List functions.
pub fn list_functions(
&self,
+56 -125
View File
@@ -9,14 +9,14 @@ mod ipc;
mod query;
use clap::Parser;
use cli::{Cli, Commands, DaemonCommands};
use cli::{Cli, Commands};
use config::Config;
use error::GhidraError;
use format::{auto_detect_format, DefaultFormatter, Formatter, OutputFormat};
use ghidra::bridge::{self, BridgeStartMode, BridgeStatus};
use ghidra::GhidraClient;
use ipc::client::BridgeClient;
use std::path::{Path, PathBuf};
use std::path::PathBuf;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::Layer;
@@ -66,7 +66,11 @@ fn main() {
.unwrap();
rt.block_on(run_setup(cli))
}
Commands::Daemon(_) => handle_daemon_command_dispatch(cli),
Commands::Start { .. }
| Commands::Stop { .. }
| Commands::Restart { .. }
| Commands::Status { .. }
| Commands::Ping { .. } => handle_bridge_command(cli),
_ => run_command(cli),
};
@@ -101,7 +105,6 @@ fn requires_bridge(command: &Commands) -> bool {
command,
Commands::Import(_)
| Commands::Analyze(_)
| Commands::Quick(_)
| Commands::Query(_)
| Commands::Decompile(_)
| Commands::Function(_)
@@ -130,7 +133,6 @@ fn extract_project_from_command(command: &Commands) -> Option<String> {
match command {
Commands::Import(args) => args.project.clone(),
Commands::Analyze(args) => args.project.clone(),
Commands::Quick(args) => args.project.clone(),
Commands::Query(args) => args.project.clone(),
Commands::Summary(args) => args.options.project.clone(),
Commands::Decompile(args) => args.options.project.clone(),
@@ -403,96 +405,37 @@ fn run_with_bridge(cli: Cli) -> anyhow::Result<()> {
}
}
Commands::Quick(args) => {
let binary_path = PathBuf::from(&args.binary);
if !binary_path.exists() {
anyhow::bail!("Binary not found: {}", args.binary);
}
eprintln!("Quick analysis of {}...", args.binary);
// Reuse running bridge instead of re-importing in a fresh one
let (client, port) = if let Some(port) = bridge::is_bridge_running(&project_path) {
_ => {
// For all bridge commands (including Analyze), ensure bridge is running
let client = if let Some(port) = bridge::is_bridge_running(&project_path) {
let client = BridgeClient::new(port);
verify_bridge(&client)?;
eprintln!("[1/3] Importing binary...");
let result = client.import_binary(&args.binary, None)?;
// import result has the newly-imported program name
let program_name = result
.get("program")
.and_then(|p| p.as_str())
.unwrap_or("unknown")
.to_string();
client.open_program(&program_name)?;
(client, port)
client
} else {
eprintln!("[1/3] Importing binary...");
let port = bridge::ensure_bridge_running(
&project_path,
&ghidra_install_dir,
BridgeStartMode::Import {
binary_path: args.binary.clone(),
},
)?;
let client = BridgeClient::new(port);
client.program_info()?;
(client, port)
};
eprintln!("[2/3] Running analysis...");
client.analyze()?;
eprintln!("[3/3] Done!");
eprintln!("Analysis complete. The bridge is running on port {}.", port);
eprintln!();
eprintln!("Run queries like:");
eprintln!(" ghidra function list");
eprintln!(" ghidra decompile main");
eprintln!(" ghidra summary");
let info = client.program_info()?;
json!({
"command": "quick",
"program": info.get("name").and_then(|n| n.as_str()).unwrap_or("unknown"),
"status": "success",
"port": port,
"data": info
})
}
// Analyze uses the generic dispatch path via execute_via_bridge
_ => {
// For query commands (including Analyze), ensure bridge is running
if bridge::is_bridge_running(&project_path).is_none() {
// Need a program name to start the bridge
let program = extract_program_from_command(&cli.command)
// Auto-start bridge - use specific program if available, otherwise project mode
let mode = if let Some(program) = extract_program_from_command(&cli.command)
.or_else(|| config.get_default_program())
.ok_or_else(|| {
anyhow::anyhow!(
"No bridge running and no default program configured.\n\
Import a binary first: ghidra import <binary>\n\
Or set a default: ghidra set-default program <name>"
)
})?;
{
BridgeStartMode::Process {
program_name: program,
}
} else {
BridgeStartMode::Project
};
eprintln!("Starting Ghidra bridge...");
let port = bridge::ensure_bridge_running(
&project_path,
&ghidra_install_dir,
BridgeStartMode::Process {
program_name: program,
},
mode,
)?;
eprintln!("Bridge ready.");
let client = BridgeClient::new(port);
execute_via_bridge(&client, &cli.command)?
} else {
let client = connect_to_bridge(&project_path)?;
verify_bridge(&client)?;
BridgeClient::new(port)
};
// Switch to requested program if it differs from the bridge's current program
if let Some(requested_program) = extract_program_from_command(&cli.command) {
let info = client.program_info()?;
// Switch to requested program if it differs from the bridge's current program
if let Some(requested_program) = extract_program_from_command(&cli.command) {
if let Ok(info) = client.program_info() {
let current = info
.get("name")
.and_then(|n| n.as_str())
@@ -500,10 +443,12 @@ fn run_with_bridge(cli: Cli) -> anyhow::Result<()> {
if current != requested_program {
client.open_program(&requested_program)?;
}
} else {
client.open_program(&requested_program)?;
}
execute_via_bridge(&client, &cli.command)?
}
execute_via_bridge(&client, &cli.command)?
}
};
@@ -765,33 +710,18 @@ fn execute_via_bridge(
}
}
/// Dispatch daemon (bridge management) commands.
fn handle_daemon_command_dispatch(cli: Cli) -> anyhow::Result<()> {
/// Dispatch bridge management commands (top-level start/stop/restart/status/ping).
fn handle_bridge_command(cli: Cli) -> anyhow::Result<()> {
match cli.command {
Commands::Daemon(cmd) => match cmd {
DaemonCommands::Start {
project,
program,
port: _,
foreground: _,
} => handle_bridge_start(project, program),
DaemonCommands::Stop { project } => handle_bridge_stop(project),
DaemonCommands::Restart {
project,
program,
port: _,
} => {
handle_bridge_stop(project.clone())?;
std::thread::sleep(std::time::Duration::from_secs(1));
handle_bridge_start(project, program)
}
DaemonCommands::Status { project } => handle_bridge_status(project),
DaemonCommands::Ping { project } => handle_bridge_ping(project),
DaemonCommands::ClearCache { project: _ } => {
println!("Cache is managed by the bridge process");
Ok(())
}
},
Commands::Start { project, program } => handle_bridge_start(project, program),
Commands::Stop { project } => handle_bridge_stop(project),
Commands::Restart { project, program } => {
handle_bridge_stop(project.clone())?;
std::thread::sleep(std::time::Duration::from_secs(1));
handle_bridge_start(project, program)
}
Commands::Status { project } => handle_bridge_status(project),
Commands::Ping { project } => handle_bridge_ping(project),
_ => unreachable!(),
}
}
@@ -823,12 +753,10 @@ fn handle_bridge_start(project: Option<String>, program: Option<String>) -> anyh
// Determine start mode
let mode = if let Some(prog) = program {
BridgeStartMode::Process { program_name: prog }
} else {
// Need a program name
let prog = config.get_default_program().ok_or_else(|| {
anyhow::anyhow!("No program specified. Use --program <name> or set a default.")
})?;
} else if let Some(prog) = config.get_default_program() {
BridgeStartMode::Process { program_name: prog }
} else {
BridgeStartMode::Project
};
println!("Starting bridge for project: {}", project_path.display());
@@ -866,6 +794,17 @@ fn handle_bridge_status(project: Option<String>) -> anyhow::Result<()> {
println!(" PID: {}", pid);
println!(" Port: {}", port);
println!(" Project: {}", project_path.display());
// Try to get extended info from the bridge
let client = BridgeClient::new(port);
if let Ok(info) = client.bridge_info() {
if let Some(prog) = info.get("current_program").and_then(|v| v.as_str()) {
println!(" Current program: {}", prog);
}
if let Some(count) = info.get("program_count").and_then(|v| v.as_u64()) {
println!(" Programs: {}", count);
}
}
}
BridgeStatus::Stopped => {
println!("No bridge running for project: {}", project_path.display());
@@ -944,7 +883,7 @@ async fn run_setup(cli: Cli) -> anyhow::Result<()> {
let client = GhidraClient::new(config)?;
if client.verify_installation().is_ok() {
println!("Verification passed!");
println!("\nYou can now run: ghidra quick <binary>");
println!("\nYou can now run: ghidra import <binary> --project <name>");
} else {
println!("Verification failed - analyzeHeadless not found");
println!(" The installation may be incomplete.");
@@ -1197,14 +1136,6 @@ fn verify_bridge(client: &BridgeClient) -> anyhow::Result<()> {
Ok(())
}
/// Connect to a running bridge for a project.
fn connect_to_bridge(project_path: &Path) -> anyhow::Result<BridgeClient> {
let port = bridge::is_bridge_running(project_path).ok_or_else(|| {
anyhow::anyhow!("Bridge not running for project: {}", project_path.display())
})?;
Ok(BridgeClient::new(port))
}
/// Resolve a project name to its full path on disk.
fn resolve_project_path(project: &Option<String>, config: &Config) -> anyhow::Result<PathBuf> {
let project_name = project
-1
View File
@@ -122,7 +122,6 @@ impl DaemonTestHarness {
let mut cmd =
assert_cmd::Command::cargo_bin("ghidra").expect("Failed to find ghidra binary");
let result = cmd
.arg("daemon")
.arg("start")
.arg("--project")
.arg(project)
+3 -36
View File
@@ -25,7 +25,6 @@ fn test_daemon_start() {
.unwrap()
.arg("--project")
.arg(TEST_PROJECT)
.arg("daemon")
.arg("status")
.assert()
.success();
@@ -47,7 +46,6 @@ fn test_daemon_status() {
.unwrap()
.arg("--project")
.arg(TEST_PROJECT)
.arg("daemon")
.arg("status")
.assert()
.success()
@@ -70,7 +68,6 @@ fn test_daemon_ping() {
.unwrap()
.arg("--project")
.arg(TEST_PROJECT)
.arg("daemon")
.arg("ping")
.assert()
.success();
@@ -78,28 +75,6 @@ fn test_daemon_ping() {
drop(harness);
}
#[test]
#[serial]
fn test_daemon_clear_cache() {
require_ghidra!();
ensure_test_project(TEST_PROJECT, TEST_PROGRAM);
let harness =
DaemonTestHarness::new(TEST_PROJECT, TEST_PROGRAM).expect("Failed to start daemon");
Command::cargo_bin("ghidra")
.unwrap()
.arg("--project")
.arg(TEST_PROJECT)
.arg("daemon")
.arg("clear-cache")
.assert()
.success();
drop(harness);
}
#[test]
#[serial]
fn test_daemon_lifecycle() {
@@ -114,7 +89,6 @@ fn test_daemon_lifecycle() {
.unwrap()
.arg("--project")
.arg(TEST_PROJECT)
.arg("daemon")
.arg("status")
.assert()
.success()
@@ -124,7 +98,6 @@ fn test_daemon_lifecycle() {
.unwrap()
.arg("--project")
.arg(TEST_PROJECT)
.arg("daemon")
.arg("ping")
.assert()
.success();
@@ -133,7 +106,6 @@ fn test_daemon_lifecycle() {
.unwrap()
.arg("--project")
.arg(TEST_PROJECT)
.arg("daemon")
.arg("stop")
.assert()
.success();
@@ -153,7 +125,6 @@ fn test_daemon_stop() {
.unwrap()
.arg("--project")
.arg(TEST_PROJECT)
.arg("daemon")
.arg("stop")
.assert()
.success();
@@ -162,11 +133,10 @@ fn test_daemon_stop() {
.unwrap()
.arg("--project")
.arg(TEST_PROJECT)
.arg("daemon")
.arg("status")
.assert()
.success()
.stdout(predicate::str::contains("No daemon running"));
.stdout(predicate::str::contains("No bridge running"));
drop(harness);
}
@@ -185,7 +155,6 @@ fn test_daemon_restart() {
.unwrap()
.arg("--project")
.arg(TEST_PROJECT)
.arg("daemon")
.arg("restart")
.arg("--program")
.arg(TEST_PROGRAM)
@@ -196,7 +165,6 @@ fn test_daemon_restart() {
.unwrap()
.arg("--project")
.arg(TEST_PROJECT)
.arg("daemon")
.arg("stop")
.assert()
.success();
@@ -218,13 +186,12 @@ fn test_daemon_start_when_running() {
.unwrap()
.arg("--project")
.arg(TEST_PROJECT)
.arg("daemon")
.arg("start")
.arg("--program")
.arg(TEST_PROGRAM)
.assert()
.failure()
.stderr(predicate::str::contains("already running"));
.success()
.stdout(predicate::str::contains("already running"));
drop(harness);
}
-26
View File
@@ -240,29 +240,3 @@ fn test_import_existing_program() {
.success();
}
#[test]
#[serial]
fn test_quick() {
require_ghidra!();
let project = unique_project_name("quick");
let binary = common::fixture_binary();
Command::cargo_bin("ghidra")
.unwrap()
.arg("quick")
.arg(binary.to_str().unwrap())
.arg("--project")
.arg(&project)
.timeout(std::time::Duration::from_secs(300))
.assert()
.success();
Command::cargo_bin("ghidra")
.unwrap()
.arg("project")
.arg("delete")
.arg(&project)
.assert()
.success();
}
-5
View File
@@ -30,7 +30,6 @@ fn test_stale_files_cleaned_on_restart() {
.unwrap()
.arg("--project")
.arg(TEST_PROJECT)
.arg("daemon")
.arg("ping")
.timeout(Duration::from_secs(30))
.assert()
@@ -52,7 +51,6 @@ fn test_stale_files_cleaned_on_restart() {
.unwrap()
.arg("--project")
.arg(TEST_PROJECT)
.arg("daemon")
.arg("ping")
.timeout(Duration::from_secs(30))
.assert()
@@ -80,7 +78,6 @@ fn test_recovery_after_crash() {
.unwrap()
.arg("--project")
.arg(TEST_PROJECT)
.arg("daemon")
.arg("ping")
.timeout(Duration::from_secs(30))
.assert()
@@ -102,7 +99,6 @@ fn test_recovery_after_crash() {
.unwrap()
.arg("--project")
.arg(TEST_PROJECT)
.arg("daemon")
.arg("ping")
.timeout(Duration::from_secs(30))
.assert()
@@ -126,7 +122,6 @@ fn test_bridge_not_ready_error() {
.unwrap()
.arg("--project")
.arg(TEST_PROJECT)
.arg("daemon")
.arg("ping")
.timeout(Duration::from_secs(30))
.assert()