-
Notifications
You must be signed in to change notification settings - Fork 57
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
Issue with callback functions #120
Comments
Probably several reasons:
|
Although not entirely production ready, and somewhat a shameless self-plug, I can recommend use icrate::Foundation::{NSPipe, NSTask, NSString, NSArray};
use block2::ConcreteBlock;
use objc2::ClassType;
fn main() -> Result<(), Box<dyn std::error::Error>> {
unsafe {
let pipe = NSPipe::pipe();
let tk = NSTask::init(NSTask::alloc());
let s = NSString::from_str("/bin/echo");
tk.setLaunchPath(Some(&s));
let strings = vec![
NSString::from_str("Hello"),
NSString::from_str("World"),
];
tk.setArguments(Some(&NSArray::from_vec(strings)));
tk.setStandardOutput(Some(&pipe));
tk.setStandardError(Some(&pipe));
let read_handle = pipe.fileHandleForReading();
let handler = ConcreteBlock::new(|_file_handle| {
println!("Output has been captured...");
});
let handler = handler.copy();
read_handle.setReadabilityHandler(Some(&handler));
read_handle.waitForDataInBackgroundAndNotify();
tk.launch();
tk.waitUntilExit();
read_handle.closeFile();
}
Ok(())
} |
Thanks @madsmtm, your code helped a lot. I now have a better feel for the macos-specific code that I could test in my application. Below is what I came up with for running a command with Cargo manifest file[package]
name = "testing"
version = "0.1.0"
edition = "2021"
[dependencies]
icrate = { version = "0.0.3", features= [ "block", "Foundation", "Foundation_NSFileHandle", "Foundation_NSArray", "Foundation_NSTask", "Foundation_NSString", "Foundation_NSURL", "Foundation_NSData", "Foundation_NSPipe" ]}
block2 = "0.2.0"
objc2 = "0.4.0" Main codeuse icrate::Foundation::{NSPipe, NSTask, NSString, NSArray, NSData, NSDictionary, NSURL};
use block2::ConcreteBlock;
use objc2::ClassType;
use objc2::msg_send;
use objc2::runtime::Object;
use objc2::rc::autoreleasepool;
fn nsdata_to_string(ll: usize, data: *mut Object) -> Option<String> {
unsafe {
let alloc_nsstring = NSString::alloc();
let nsdata = &* (data as *const NSData);
let id_nsstring = NSString::initWithData_encoding(alloc_nsstring, nsdata, 4);
if let Some(nsstring) = id_nsstring {
let mut ret = String::with_capacity(ll);
autoreleasepool(|pool| {
let v = nsstring.as_str(pool);
ret.push_str(v);
});
Some(ret)
} else {
None
}
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
unsafe {
let pipe = NSPipe::pipe();
let tk = NSTask::init(NSTask::alloc());
let pstring = "/bin/echo".to_string();
let pstr = pstring.as_str();
let s = NSString::from_str(pstr);
let pp = NSURL::alloc();
let p = NSURL::initFileURLWithPath(pp, &s);
let strings = vec![
NSString::from_str("Hello"),
NSString::from_str("World"),
];
let k = NSString::from_str("NSUnbufferedIO");
let v = NSString::from_str("YES");
let dict = NSDictionary::from_keys_and_objects(&[&*k], vec![v]);
tk.setExecutableURL(Some(&p));
tk.setArguments(Some(&NSArray::from_vec(strings)));
tk.setEnvironment(Some(&dict));
tk.setStandardOutput(Some(&pipe));
tk.setStandardError(Some(&pipe));
let read_handle = pipe.fileHandleForReading();
let handler = ConcreteBlock::new(|handle| {
let data: *mut Object = msg_send![handle, availableData];
let ll: usize = msg_send![data, length];
if ll != 0 {
if let Some(output) = nsdata_to_string(ll, data) {
println!("Output: {}", output);
}
}
});
let handler = handler.copy();
read_handle.setReadabilityHandler(Some(&handler));
read_handle.waitForDataInBackgroundAndNotify();
if let Err(ex) = tk.launchAndReturnError() {
return Err(ex.to_string().into());
}
tk.waitUntilExit();
if let Err(ex) = read_handle.closeAndReturnError() {
return Err(ex.to_string().into());
}
if tk.terminationStatus() != 0 {
return Err("Task failed!".into());
}
}
Ok(())
} |
I'm trying to execute a command and capture its output via
NSTask
, as a way to run external commands within an app bundle (sandbox issues andPATH
visibility).The code below executes successfully, but the command output is printed directly to stdout, instead of being captured. That means that my callback (
set_readability_handler
) is never registered or invoked.I suspect that it could be a method signature issue or something fundamental that I'm missing. Any help would be appreciated.
The text was updated successfully, but these errors were encountered: