Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix/progress bar loop lock release #132

Merged
merged 2 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 15 additions & 63 deletions crates/client/src/commander.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,22 +378,30 @@ impl Commander {

let cargo_thread = std::thread::spawn(move || -> Result<(), Error> {
let output = Self::expand_package(&name);
// release progress bar loop here as the expansion is the longest part
// further we cannot release after parsing as parsing can panic which will not
// release the lock
c_mutex.store(false, std::sync::atomic::Ordering::SeqCst);
let output = output.expect("Program expansion failed");

if output.status.success() {
let code = String::from_utf8(output.stdout).unwrap();
let code = String::from_utf8(output.stdout).expect("Reading stdout failed");

let idl_program = idl::parse_to_idl_program(name, &code)?;
let mut vec = c_shared_mutex.lock().unwrap();
let mut vec_fuzzer = c_shared_mutex_fuzzer.lock().unwrap();
let mut vec = c_shared_mutex
.lock()
.expect("Acquire IdlProgram lock failed");
let mut vec_fuzzer = c_shared_mutex_fuzzer
.lock()
.expect("Acquire Fuzzer data lock failed");

vec.push(idl_program);
vec_fuzzer.push((code, lib_path));

c_mutex.store(false, std::sync::atomic::Ordering::SeqCst);
Ok(())
} else {
let error_text = String::from_utf8(output.stderr).unwrap();
c_mutex.store(false, std::sync::atomic::Ordering::SeqCst);
let error_text =
String::from_utf8(output.stderr).expect("Reading stderr failed");
Err(Error::ReadProgramCodeFailed(error_text))
}
});
Expand Down Expand Up @@ -428,7 +436,7 @@ impl Commander {
/// # Returns
/// - Returns a `std::process::Output` object containing the outcome of the cargo command execution. This includes
/// the expanded source code in the command's stdout, along with any stderr output and the exit status.
fn expand_package(package_name: &str) -> std::process::Output {
fn expand_package(package_name: &str) -> std::io::Result<std::process::Output> {
std::process::Command::new("cargo")
.arg("+nightly-2023-12-28")
.arg("rustc")
Expand All @@ -437,63 +445,7 @@ impl Commander {
.arg("--")
.arg("-Zunpretty=expanded")
.output()
.unwrap()
}

/// Retrieves Rust `use` statements from the expanded source code of the "program_client" package.
///
/// This function initiates an expansion of the "program_client" package to obtain
/// the macro-expanded source code. It then parses this source to extract all `use` statement declarations,
/// returning them as a vector of `syn::ItemUse`. If no `use` statements are found, a default import for
/// `trdelnik_client::*` is included in the returned vector to ensure the caller has at least one valid import.
///
/// # Returns
/// A `Vec<syn::ItemUse>` containing the parsed `use` statements from the "program_client" package's source code.
/// If no `use` statements are found, the vector contains a default `use trdelnik_client::*;` statement.
///
/// # Errors
/// - Returns an `Error` if the package expansion fails, either due to command execution failure or issues
/// parsing the expanded code into a UTF-8 string.
/// - Propagates errors encountered while acquiring locks on shared state or parsing `use` statements from the code.
#[throws]
pub async fn get_program_client_imports() -> Vec<syn::ItemUse> {
let shared_mutex = std::sync::Arc::new(std::sync::Mutex::new(String::new()));

let mutex = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(true));
let c_mutex = std::sync::Arc::clone(&mutex);

let c_shared_mutex = std::sync::Arc::clone(&shared_mutex);

let cargo_thread = std::thread::spawn(move || -> Result<(), Error> {
let output = Self::expand_package("program_client");

if output.status.success() {
let mut code = c_shared_mutex.lock().unwrap();
code.push_str(&String::from_utf8(output.stdout)?);

c_mutex.store(false, std::sync::atomic::Ordering::SeqCst);
Ok(())
} else {
// command failed leave unmodified
c_mutex.store(false, std::sync::atomic::Ordering::SeqCst);
Ok(())
}
});

Self::expand_progress_bar("program_client", &mutex);

cargo_thread.join().unwrap()?;

let code = shared_mutex.lock().unwrap();
let code = code.as_str();
let mut use_modules: Vec<syn::ItemUse> = vec![];
Self::get_use_statements(code, &mut use_modules)?;
if use_modules.is_empty() {
use_modules.push(syn::parse_quote! { use trdelnik_client::*; })
}
use_modules
}

#[throws]
pub fn get_use_statements(code: &str, use_modules: &mut Vec<syn::ItemUse>) {
for item in syn::parse_file(code).unwrap().items.into_iter() {
Expand Down
26 changes: 20 additions & 6 deletions crates/client/src/test_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,7 @@ impl TestGenerator {
commander.build_anchor_project().await?;
// expands programs within programs folder
self.expand_programs().await?;
// expands program_client and obtains
// use statements
// obtain use statements
// if program_client is not yet initialized
// use statements are set to default
self.get_program_client_imports().await?;
Expand Down Expand Up @@ -205,7 +204,9 @@ impl TestGenerator {
commander.build_anchor_project().await?;
// expand programs
self.expand_programs().await?;
// expand program_client
// obtain use statements
// if program_client is not yet initialized
// use statements are set to default
self.get_program_client_imports().await?;
// initialize program client if it is not yet initialized
self.init_program_client().await?;
Expand Down Expand Up @@ -246,7 +247,9 @@ impl TestGenerator {
commander.build_anchor_project().await?;
// expand programs
self.expand_programs().await?;
// expand program_client
// obtain use statements
// if program_client is not yet initialized
// use statements are set to default
self.get_program_client_imports().await?;
// add/update program_client
self.add_program_client().await?;
Expand All @@ -260,10 +263,21 @@ impl TestGenerator {
(self.idl, self.codes_libs_pairs) =
Commander::expand_program_packages(&self.packages).await?;
}
/// Expand .program_client source code and obtain its use statements.
/// Get user specified use statements from .program_client lib.
#[throws]
async fn get_program_client_imports(&mut self) {
self.use_tokens = Commander::get_program_client_imports().await?;
let lib_path = construct_path!(self.root, PROGRAM_CLIENT_DIRECTORY, SRC_DIRECTORY, LIB);
if lib_path.exists() {
let code = fs::read_to_string(lib_path).await.unwrap_or_else(|_e| {
println!("\x1b[1;93mWarning\x1b[0m: Unable to read .program_client, use statements set to default.");
String::default()
});
Commander::get_use_statements(&code, &mut self.use_tokens)?;
}
if self.use_tokens.is_empty() {
self.use_tokens
.push(syn::parse_quote! { use trdelnik_client::*; })
}
}

/// Checks if the whole folder structure for .program_client is already
Expand Down
Loading