This is my code so far
use std::process::Command;
fn main() {
...
Command::new(r"C:\Program Files (x86)\MSI Afterburner\MSIAfterburner.exe")
.spawn()
.unwrap();
...
}
And I got this error:
{ code: 740, message: "The requested operation requires elevation." }
I found this which is probably what I need but I don't know how to do it
If anyone could make an example on how to do it that would be gladly appreciated.
I've found a workaround
use std::process::Command;
fn main(){
Command::new("cmd.exe")
.args(["/C",r"C:\Program Files (x86)\MSI Afterburner\MSIAfterburner.exe"])
.spawn()
.unwrap();
}
Kinda ugly but works.
Related
I'm writing a Rust program which will create a directory based on user input. I would like to know how to panic with my own text when error occurs, like Permission Error etc...
fn create_dir(path: &String) -> std::io::Result<()> {
std::fs::create_dir_all(path)?;
Ok(())
}
This will do nothing when error occcurs
For this case, the simplest way is to use unwrap_or_else():
fn create_dir(path: &str) {
std::fs::create_dir_all(path)
.unwrap_or_else(|e| panic!("Error creating dir: {}", e));
}
Note that I also changed the argument type, for the reasons described here.
However, it would be more idiomatic to accept a &Path or AsRef<Path>.
use std::fs;
use std::path::Path;
fn create_dir<P: AsRef<Path>>(path: P) {
fs::create_dir_all(path)
.unwrap_or_else(|e| panic!("Error creating dir: {}", e));
}
If I have a file like this:
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
Err("May
June")?
}
I get this result:
Error: "May\nJune"
Is it possible to get the unquoted string on output? Like this:
Error: May
June
I tried this:
Err("May
June").map_err(|e|
format!("{:?}", e)
)?
but it just made it worse:
Error: "\"May\\nJune\""
You have to print the error yourself instead of relying on the default fallback implementation.
main() -> Result<…> prints Debug version of the error (where strings are escaped). It's intended as a quick'n'dirty solution for examples or playpens, and not for real programs where anyone would care about presentation of the output.
Use:
fn main() {
if let Err(e) = run() {
eprintln!("{}", e);
std::process::exit(1);
}
}
fn run() -> Result<(), Box<dyn Error>> {
// etc
}
It will print the error using Display formatting.
There's nothing special about main()'s built-in error handling, so you're not losing anything by printing the error yourself.
There's also an alternative solution of implementing a custom Debug implementation on errors to make the Debug implementation print a non-debug one, but IMHO that's a hack, and needs more code than just doing the straightforward print. If you want that hack, have a look at the anyhow crate.
It might be overkill to pull in an extra dependency for this, but you can use the terminator crate, which offers a new error type intended to be returned from main that delegates to the Display implementation when printed with Debug. Then your example would look like this...
use terminator::Terminator;
fn main() -> Result<(), Terminator> {
Err("May
June")?
}
...and the output would be this:
Error: May
June
I am new to Rust and working on the exercise in Chapter 12.3 in the book.
I am pretty confident that my code is the same as that in the book (hard to tell for sure because of the 'snips'). However I get an unresolved import error when I try cargo build or cargo run from the project directory, minigrep/
src/main.rs
use std::env;
use std::process;
use minigrep;
use minigrep::Config;
fn main() {
let args: Vec<String> = env::args().collect();
let config = Config::new(&args).unwrap_or_else(|err| {
println!("Problem parsing args: {}", err);
process::exit(1);
});
println!("Searching for {}", config.query);
println!("In file {}", config.filename);
if let Err(e) = minigrep::run(config) {
println!("Application error: {}", e);
process::exit(1);
}
}
src/lib.rs
use std::fs;
use std::error::Error;
pub struct Config {
pub query: String,
pub filename: String,
}
impl Config {
pub fn new(args: &[String]) -> Result <Config, &'static str> {
if args.len() < 3 {
return Err("not enough args");
}
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)?;
println!("With text:\n {}", contents);
Ok(())
}
There is a contradiction between the code samples for the exercise in chapter 12.3 and the earlier section in chapter 7: '7.2 -- Modules and use to control scope -- Separating modules into different files'.
Using 7.2's syntax complies:
mod lib; //.. instead of 'use minigrep'
use lib::Config; //.. instead of 'use minigrep::Config'
Neither of the above answers is correct. Using cargo clean is the correct solution. The incremental build process that produces that red underline in the IDE is a result of cached information about the program and library.
$ cargo clean
This seems to be a VSCode issue. Simply restarting VSCode makes the error go away, as discussed on this GitHub issue: https://github.com/rust-lang/vscode-rust/issues/686
I had this issue because I accidentally chose the wrong file name for the lib.rs. Make sure the file is named lib.rs without a typo. Other file names do not work here because of the use statement.
When you write use minigrep::Config, the compiler will look for a lib.rs file in the current project minigrep to resolve the imports.
I just ran across the same problem when reviewing The Rust Programming Language. The way I got it to compile was to remove the line use minigrep; from src/main.rs and add extern crate minigrep to the top of the file. The other file can stay as it is. Not sure if this a typo in the book (if it is then it is in multiple versions) or if there is a change to the behavior of the Rust compiler to accommodate the new syntax and we are just using a version that is too old. For comparison my version is 1.31.0.
In Python I can:
from distutils import spawn
cmd = spawn.find_executable("commandname")
I tried something like the code below, but it it assumes you're on unix-like system with /usr/bin/which available(also it involves execution of external command which I want to avoid):
use std::process::Command;
let output = Command::new("which")
.arg("commandname")
.unwrap_or_else(|e| /* handle error here */)
What is the simplest way to do this in Rust?
I found a crate that solves the problem: which. It includes Windows support, even accounting for PATHEXT.
I'd probably grab the environment variable and iterate through it, returning the first matching path:
use std::env;
use std::path::{Path, PathBuf};
fn find_it<P>(exe_name: P) -> Option<PathBuf>
where P: AsRef<Path>,
{
env::var_os("PATH").and_then(|paths| {
env::split_paths(&paths).filter_map(|dir| {
let full_path = dir.join(&exe_name);
if full_path.is_file() {
Some(full_path)
} else {
None
}
}).next()
})
}
fn main() {
println!("{:?}", find_it("cat"));
println!("{:?}", find_it("dog"));
}
This is probably ugly on Windows as you'd have to append the .exe to the executable name. It should also potentially be extended to only return items that are executable, which is again platform-specific code.
Reviewing the Python implementation, it appears they also support an absolute path being passed. That's up to you if the function should support that or not.
A quick search on crates.io returned one crate that may be useful: quale, although it currently says
currently only works on Unix-like operating systems.
It wouldn't surprise me to find out there are others.
Here's some ugly code that adds .exe to the end if it's missing, but only on Windows.
#[cfg(not(target_os = "windows"))]
fn enhance_exe_name(exe_name: &Path) -> Cow<Path> {
exe_name.into()
}
#[cfg(target_os = "windows")]
fn enhance_exe_name(exe_name: &Path) -> Cow<Path> {
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
let raw_input: Vec<_> = exe_name.as_os_str().encode_wide().collect();
let raw_extension: Vec<_> = OsStr::new(".exe").encode_wide().collect();
if raw_input.ends_with(&raw_extension) {
exe_name.into()
} else {
let mut with_exe = exe_name.as_os_str().to_owned();
with_exe.push(".exe");
PathBuf::from(with_exe).into()
}
}
// At the top of the `find_it` function:
// let exe_name = enhance_exe_name(exe_name.as_ref());
If my understanding is correct, the following code should produce an executable file. However it doesn't; it gets created, but the permissions specified aren't applied. What am I doing wrong?
use std::fs;
use std::os::unix::PermissionsExt;
fn main() {
fs::File::create("somefile").unwrap()
.metadata().unwrap()
.permissions()
.set_mode(0o770);
}
Use OpenOptions:
use std::fs;
use std::os::unix::OpenOptionsExt;
fn main() {
fs::OpenOptions::new()
.create(true)
.write(true)
.mode(0o770)
.open("somefile")
.unwrap();
}
You can also use set_permissions for existing path
use std::fs;
use std::os::unix::fs::PermissionsExt;
fn main(){
fs::set_permissions("/path", fs::Permissions::from_mode(0o655)).unwrap();
}