Can't run an installed program using std::process::Command - rust

I'm writing a small CLI app to set up my development environment based on a Jira ticket, currently I'm trying to open VS Code but I get a command not found error even though I can open VS Code from withing my terminal.
// jira.rs
use std::fmt;
pub struct JiraTicket {
pub key: String,
pub number: u32,
}
impl JiraTicket {
pub fn new(key: String, number: u32) -> JiraTicket {
JiraTicket { key, number }
}
}
impl fmt::Display for JiraTicket {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}-{}", self.key, self.number)
}
}
// command.rs
pub fn open_vscode(ticket: Option<&JiraTicket>) {
let path = match ticket {
Some(path) => path.to_string(),
None => ".".to_string(),
};
let vscode_command = Command::new("code")
.arg(path)
.status()
.expect("An error ocurred while opening vs code");
if vscode_command.success() {
println!("{}", "Opened VSCode".green());
} else {
println!("{}", "Failed to open VSCode".red());
}
}
I already looked at:
Command not found when using std::process::command in rust?
Unable to use std::process::Command - No such file or directory

"code.cmd" seems to work:
let vscode_command = Command::new("code.cmd")
.arg(path)
.status()
.expect("An error ocurred while opening vs code");
I'm not sure why "code.cmd" works but "code" doesn't, though.
Might be related to rust-lang issue #37519.

Related

Cannot move out of `config.filename` which is behind a shared reference. I don't know why I got this error

I have this function
pub struct Config {
pub query: String,
pub filename: String,
}
impl Config {
pub fn new(args: &Vec<String>) -> Result<Config, &str> {
if args.len() > 3 {
return Err("Error");
}
let query = args[1].clone();
let filename = args[2].clone();
Ok(Config {query, filename})
}
}
pub fn run(config: &Config) -> Result<(), Box<dyn Error>> {
let contents = fs::read_to_string(config.filename)?;
for i in search(&config.query, &contents) {
println!("Found: {}", i);
}
Ok(())
}
I got an error "cannot move out of config.filename which is behind a shared reference" when run this
if let Err(e) = run(&config) {
println!("Error:{}", e);
process::exit(1);
}
run(&config);
I really don't know why I got this error. Can anyone please explain it? Many thanks.
When you call read_to_string(config.filename), you're moving filename (i.e. transferring ownership) into read_to_string. But you don't have ownership since run only borrows config.
Since read_to_string actually takes AsRef<Path> (i.e. anything that can be referenced as a Path), it can work with a borrowed string as well as an owned one. So you can solve the issue by simply lending filename: read_to_string (&config.filename).

Which signature is most effective when using multiple conditions or Results? How to bubble errors correctly?

Introduction
I'm learning rust and have been trying to find the right signature for using multiple Results in a single function and then returning either correct value, or exit the program with a message.
So far I have 2 different methods and I'm trying to combine them.
Context
This is what I'm trying to achieve:
fn blur(image: DynamicImage, amount: &str) -> DynamicImage {
let amount = parse_between_or_error_out("blur", amount, 0.0, 10.0);
image.brighten(amount)
}
This is what I have working now, but would like to refactor.
fn blur(image: DynamicImage, amount: &str) -> DynamicImage {
match parse::<f32>(amount) {
Ok(amount) => {
verify_that_value_is_between("blur", amount, 0.0, 10.0);
image.blur(amount)
}
_ => {
println!("Error");
process::exit(1)
}
}
}
Combining these methods
Now here's the two working methods that I'm trying to combine, to achieve this.
fn parse<T: FromStr>(value: &str) -> Result<T, <T as FromStr>::Err> {
value.parse::<T>()
}
fn verify_that_value_is_between<T: PartialOrd + std::fmt::Display>(
name: &str,
amount: T,
minimum: T,
maximum: T,
) {
if amount > maximum || amount < minimum {
println!(
"Error: Expected {} amount to be between {} and {}",
name, minimum, maximum
);
process::exit(1)
};
println!("- Using {} of {:.1}/{}", name, amount, maximum);
}
Here's what I tried
I have tried the following. I realise I'm likely doing a range of things wrong. This is because I'm still learning Rust, and I'd like any feedback that helps me learn how to improve.
fn parse_between_or_error_out<T: PartialOrd + FromStr + std::fmt::Display>(
name: &str,
amount: &str,
minimum: T,
maximum: T,
) -> Result<T, <T as FromStr>::Err> {
fn error_and_exit() {
println!(
"Error: Expected {} amount to be between {} and {}",
name, minimum, maximum
);
process::exit(1);
}
match amount.parse::<T>() {
Ok(amount) => {
if amount > maximum || amount < minimum {
error_and_exit();
};
println!("- Using {} of {:.1}/{}", name, amount, maximum);
amount
}
_ => {
error_and_exit();
}
}
}
Currently this looks quite messy, probably I'm using too many or the wrong types and the error needs to be in two places (hence the inlined function, which I know is not good practice).
Full reproducible example.
The question
How to best combine logic that is using a Result and another condition (or Result), exit with a message or give T as a result?
Comments on any of the mistakes are making are very welcome too.
You can use a crate such as anyhow to bubble your events up and handle them as needed.
Alternatively, you can write your own trait and implement it on Result.
trait PrintAndExit<T> {
fn or_print_and_exit(&self) -> T;
}
Then use it by calling the method on any type that implements it:
fn try_get_value() -> Result<bool, MyError> {
MyError { msg: "Something went wrong".to_string() }
}
let some_result: Result<bool, MyError> = try_get_value();
let value: bool = some_result.or_print_and_exit();
// Exits with message: "Error: Something went wrong"
Implementing this trait on Result could be done with:
struct MyError {
msg: String,
}
impl<T> PrintAndExit<T> for Result<T, MyError> {
fn or_print_and_exit(&self) -> T {
match self {
Ok(val) => val,
Err(e) => {
println!("Error: {}", e.msg);
std::process::exit(1);
},
}
}
}
Here are a few DRY tricks.
tl;dr:
Convert other Errors into your unified error type(s) with impl From<ExxError> for MyError;
In any function that may result in an Error, use ? as much as you can. Return Result<???, MyError> (*). ? will utilize the implicit conversion.
(*) Only if MyError is an appropriate type for the function. Always create or use the most appropriate error types. (Kinda obvious, but people often treat error types as a second-class code, pun intended)
Recommendations are in the comments.
use std::error::Error;
use std::str::FromStr;
// Debug and Display are required by "impl Error" below.
#[derive(Debug)]
enum ProcessingError {
NumberFormat{ message: String },
NumberRange{ message: String },
ProcessingError{ message: String },
}
// Display will be used when the error is printed.
// No need to litter the business logic with error
// formatting code.
impl Display for ProcessingError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ProcessingError::NumberFormat { message } =>
write!(f, "Number format error: {}", message),
ProcessingError::NumberRange { message } =>
write!(f, "Number range error: {}", message),
ProcessingError::ProcessingError { message } =>
write!(f, "Image processing error: {}", message),
}
}
}
impl Error for ProcessingError {}
// FromStr::Err will be implicitly converted into ProcessingError,
// when ProcessingError is needed. I guess this is what
// anyhow::Error does under the hood.
// Implement From<X> for ProcessingError for every X error type
// that your functions like process_image() may encounter.
impl From<FromStr::Err> for ProcessingError {
fn from(e: FromStr::Err) -> ProcessingError {
ProcessingError::NumberFormat { message: format!("{}", e) }
}
}
pub fn try_parse<T: FromStr>(value: &str) -> Result<T, ProcessingError> {
// Note ?. It will implicitly return
// Err(ProcessingError created from FromStr::Err)
Ok (
value.parse::<T>()?
)
}
// Now, we can have each function only report/handle errors that
// are relevant to it. ? magically eliminates meaningless code like
// match x { ..., Err(e) => Err(e) }.
pub fn parse_between<T>(value: &str, min_amount: T, max_amount: T)
-> Result<T, ProcessingError>
where
T: FromStr + PartialOrd + std::fmt::Display,
{
let amount = try_parse::<T>(value)?;
if amount > max_amount || amount < min_amount {
Err(ProcessingError::NumberRange {
message: format!(
"Expected value to be between {} and {} but received {}",
min_amount,
max_amount,
amount)
})
} else {
Ok(amount)
}
}
main.rs
use image::{DynamicImage};
use std::fmt::{Debug, Formatter, Display};
fn blur(image: DynamicImage, value: &str)
-> Result<DynamicImage, ProcessingError>
{
let min_amount = 0.0;
let max_amount = 10.0;
// Again, note ? in the end.
let amount = parse_between(value, min_amount, max_amount)?;
image.blur(amount)
}
// All processing extracted into a function, whose Error
// then can be handled by main().
fn process_image(image: DynamicImage, value: &str)
-> Result<DynamicImage, ProcessingError>
{
println!("applying blur {:.1}/{:.1}...", amount, max_amount);
image = blur(image, value);
// save image ...
image
}
fn main() {
let mut image = DynamicImage::new(...);
image = match process_image(image, "1") {
Ok(image) => image,
// No need to reuse print-and-exit functionality. I doubt
// you want to reuse it a lot.
// If you do, and then change your mind, you will have to
// root it out of all corners of your code. Better return a
// Result and let the caller decide what to do with errors.
// Here's a single point to process errors and exit() or do
// something else.
Err(e) => {
println!("Error processing image: {:?}", e);
std::process::exit(1);
}
}
}
Sharing my results
I'll share my results/answer as well for other people who are new to Rust. This answer is based on that of #Acidic9's answer.
The types seem to be fine
anyhow looks to be the de facto standard in Rust.
I should have used a trait and implement that trait for the Error type.
I believe the below example is close to what it might look like in the wild.
// main.rs
use image::{DynamicImage};
use app::{parse_between, PrintAndExit};
fn main() {
// mut image = ...
image = blur(image, "1")
// save image
}
fn blur(image: DynamicImage, value: &str) -> DynamicImage {
let min_amount = 0.0;
let max_amount = 10.0;
match parse_between(value, min_amount, max_amount).context("Input error") {
Ok(amount) => {
println!("applying blur {:.1}/{:.1}...", amount, max_amount);
image.blur(amount)
}
Err(error) => error.print_and_exit(),
}
}
And the implementation inside the apps library, using anyhow.
// lib.rs
use anyhow::{anyhow, Error, Result};
use std::str::FromStr;
pub trait Exit {
fn print_and_exit(self) -> !;
}
impl Exit for Error {
fn print_and_exit(self) -> ! {
eprintln!("{:#}", self);
std::process::exit(1);
}
}
pub fn try_parse<T: FromStr>(value: &str) -> Result<T, Error> {
match value.parse::<T>() {
Ok(value) => Ok(value),
Err(_) => Err(anyhow!("\"{}\" is not a valid value.", value)),
}
}
pub fn parse_between<T>(value: &str, min_amount: T, max_amount: T) -> Result<T, Error>
where
T: FromStr + PartialOrd + std::fmt::Display,
{
match try_parse::<T>(value) {
Ok(amount) => {
if amount > max_amount || amount < min_amount {
return Err(anyhow!(
"Expected value to be between {} and {} but received {}",
min_amount,
max_amount,
amount
));
};
Ok(amount)
}
Err(error) => Err(error),
}
}
Hopefully seeing this full implementation will help someone out there.
Source code.

Cannot find macro `log` in this scope when using log with Rocket

I am getting a compiler error trying to use the log crate in a package in a workspace. The other crates in the workspace are using logging without problem.
Cargo.toml:
[dependencies]
log = "^0"
rocket = "^0"
[dependencies.uuid]
version = "^0"
features = ["v4"]
lib.rs:
#![feature(proc_macro_hygiene, decl_macro)]
use rocket::{
Request,
Data,
Response
};
use rocket::request::{
self,
FromRequest,
Outcome
};
use rocket::fairing::{
Fairing,
Info,
Kind
};
use uuid::Uuid;
use std::fmt;
use log;
pub struct LoggerFairing {
service_name: &'static str
}
impl LoggerFairing {
pub fn new(service_name: &'static str) -> Self {
LoggerFairing {
service_name
}
}
}
impl Fairing for LoggerFairing {
fn info(&self) -> Info {
Info {
name: self.service_name,
kind: Kind::Request | Kind::Response
}
}
fn on_request(&self, req: &mut Request, _: &Data) {
let ip_addr = req.client_ip().map(|addr| addr.to_string())
.unwrap_or("IP Address unknown".to_string());
let method = req.method();
let url = req.uri();
let request_id = get_request_id(req);
log::info!("request {:?} from {}: {} {}", request_id, ip_addr, method, url);
}
fn on_response(&self, req: &Request, res: &mut Response) {
let request_id = get_request_id(req);
let status = res.status();
log::info!("request {:?} responded with {}", request_id, status);
}
}
fn get_request_id<'t, 'r>(req: &'t Request<'r>) -> Option<RequestId<'t>> {
match req.guard::<RequestId>() {
Outcome::Success(request_id) => Some(request_id),
_ => None
}
}
pub struct RequestId<'t> {
pub id: &'t Uuid
}
impl<'t, 'r> FromRequest<'t, 'r> for RequestId<'t> {
type Error = ();
fn from_request(req: &'t Request<'r>) -> request::Outcome<Self, Self::Error> {
let id = req.local_cache(|| Uuid::new_v4());
request::Outcome::Success(RequestId {
id
})
}
}
impl<'t> fmt::Display for RequestId<'t> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.id)
}
}
The error message:
error: cannot find macro `log` in this scope
--> utils\logging\src\lib.rs:62:9
|
62 | log::info!("request {:?} from {}: {} {}", request_id, ip_addr, method, url);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: cannot find macro `log` in this scope
--> utils\logging\src\lib.rs:71:9
|
71 | log::info!("request {:?} responded with {}", request_id, status);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
error: could not compile `logging`.
I've used several variations of the use log statement and how I'm calling the info! macro, but they all cause the same error message. I've tried specifying exact versions in Cargo.toml.
I'm stumped. This is exactly how I'm using log in other crates.
Specifying the exact version of the log crate (0.4.11) in Cargo.toml fixes this problem.
I'm assuming there is something funny happening when Cargo tries to resolve the dependencies.

catch_unwind signal SIGABRT when unwrap a Result inside it

I develop an Android app that call some Rust (stable 1.37.0) native functions via JNI. And I want to catch any panic inside them to convert it into java.lang.Error.
So, I've read about std::panic::catch_unwind and decided to try it. But I received signal Fatal signal 6 (SIGABRT), code -6 (SI_TKILL) when tried to unwrap some custom Error.
///Some custom error
#[derive(Debug)]
struct MyError;
impl Error for MyError {}
impl Display for MyError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "I'm an Error struct")
}
}
OK. Catch the error above in Rust's unit tests or executable.
fn main() {
let result = panic::catch_unwind(|| {
Result::<String, _>::Err(MyError).unwrap();
});
// works!
if let (Err(_)) = result {
println!("I'm an Error!")
}
}
SIGABRT. Call it via jni on Android
/// Some function called from an Android thread
/// args omitted
#[no_mangle]
pub unsafe extern "C" fn Java_com_example_test() {
// that won't help
panic::set_hook(Box::new(|_| {}));
let result = panic::catch_unwind(|| {
// signal Fatal signal 6 (SIGABRT), code -6 (SI_TKILL)
Result::<String, _>::Err(MyError).unwrap();
// BUT! These code will not abort the process and work properly
//inner::unwrap(Result::<String, _>::Err(MyError));
//Result::<(), _>::Err("error".to_string()).unwrap();
()
});
// doesn't work!
if let (Err(_)) = result {
println!("I'm an Error!")
}
}
mod inner {
#[inline]
pub fn unwrap<T, E: ::std::fmt::Debug>(r: Result<T, E>) -> T {
match r {
Ok(t) => t,
Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", e),
}
}
#[inline(never)]
#[cold]
fn unwrap_failed<E: ::std::fmt::Debug>(msg: &str, error: E) -> ! {
panic!("{}: {:?}", msg, error)
}
}
OK. Use futures catch_unwind on Android.
/// Some function called from an Android thread
/// args omitted
#[no_mangle]
pub unsafe extern "C" fn Java_com_example_test2() {
let result = futures::lazy(|| {
if true {
Err(MyError)
} else {
Ok("error".to_string())
}
.unwrap();
futures::future::ok::<_, ()>(())
})
.catch_unwind()
.wait();
// works!
if let (Err(_)) = result {
println!("I'm an Error!")
}
}
Same, but on the Playground.
I don't understand what is a difference between these variants? They are all use the panic! macro that work properly inside panic::catch_unwind.

How do I fix a segfault when the lifetime of a dynamically loaded library expires?

I'm using the following scheme:
Start the main program.
Dynamically load / unload necessary libraries without interrupting the main program.
The main program terminates.
All of the code (the main program, the dynamic library) is written in Rust and it is all compiled with -Cprefer-dynamic.
The dynamic library contains a Plugin struct that implements the plugin::Plugin trait with a new function that returns a boxed trait object (plugin::Plugin).
Dynamic library example:
#[derive(Debug)]
pub struct Plugin;
impl Plugin {
#[no_mangle]
pub fn new() -> Box<plugin::Plugin> {
println!("IN NEW!");
Box::new(Plugin)
}
}
impl plugin::Plugin for Plugin {
fn test(&mut self) -> plugin::Result<()> {
println!("IN TEST!");
Ok(())
}
}
plugin::Plugin is a trait:
pub trait Plugin: Debug {
fn test(&mut self) -> Result<()>;
}
Main program:
fn main() {
env_logger::init().unwrap();
info!("[MAIN]<-");
if let Ok(mut plugins) = load(Path::new("plugins/")) {
for (path, plugin) in plugins.iter_mut() {
debug!("path: {:?}, plugin: {:?}", path, plugin);
plugin.plugin.test();
}
thread::sleep(Duration::from_secs(30));
// <- as soon as the plugins is beyond his lifetime, segmentation fault.
}
info!("[MAIN]->");
}
fn load(path: & Path) -> Result<HashMap<String, Plugin>> {
let mut plugins = HashMap::new();
let valid_extensions: [& OsStr; 3] = ["dylib".as_ref(), "so".as_ref(), "dll".as_ref()];
for dir_entry in try!(path.read_dir()) {
let path = try!(dir_entry).path();
if path.extension().is_none() || !valid_extensions.contains(& path.extension().unwrap()) {
warn!("invalid dynamic library extension; extension: {:?}", path.extension());
continue
}
let key = path.clone().into_os_string().into_string().unwrap();
let lib = DynamicLibrary::open(Some(& path)).unwrap();
let new: extern fn() -> Box<plugin::Plugin> = unsafe {
std::mem::transmute(lib.symbol::<u8>("new").unwrap())
};
let plugin = Plugin {
_lib: lib,
plugin: new(),
};
plugins.insert(key.clone(), plugin);
}
Ok(plugins)
}
struct Plugin {
_lib: DynamicLibrary,
pub plugin: Box<plugin::Plugin>,
}
Is it even correct to use FFI for this type of Rust-Rust interaction?

Resources