Better support for windows

This commit is contained in:
Lej77 2020-02-01 02:37:09 +01:00
parent e5eb58ec5f
commit 48cd7a3c7d
5 changed files with 98 additions and 33 deletions

11
Cargo.lock generated
View file

@ -1082,7 +1082,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1208,15 +1207,6 @@ dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "term"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
version = "0.11.0"
@ -1500,7 +1490,6 @@ dependencies = [
"checksum syn-mid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd3937748a7eccff61ba5b90af1a20dbf610858923a9192ea0ecb0cb77db1d0"
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
"checksum term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"

View file

@ -34,10 +34,8 @@ path = "shared/lib.rs"
anyhow = "1"
async-std = { version = "1", features = ["attributes", "unstable"] }
dirs = "2"
users = "^0.9"
chrono = { version = "^0.4", features = ["serde"] }
rand = "^0.7"
nix = "0.16"
strum = "0.17"
strum_macros = "0.17"
@ -50,8 +48,12 @@ serde_derive = "^1.0"
log = "0.4"
config = "^0.10"
simplelog = "0.7"
simplelog = { version = "0.7", default-features = false }
structopt = "0.3"
crossterm = "^0.15"
comfy-table= "0.0.6"
tempfile = "^3"
[target.'cfg(not(windows))'.dependencies]
users = "^0.9"
nix = "0.16"

View file

@ -8,9 +8,11 @@ use ::std::time::Duration;
use ::anyhow::Result;
use ::chrono::prelude::*;
use ::log::{debug, error, info, warn};
use ::nix::sys::signal;
use ::nix::sys::signal::Signal;
use ::nix::unistd::Pid;
#[cfg(not(windows))]
use ::nix::{
sys::signal::{self, Signal},
unistd::Pid,
};
use ::pueue::log::*;
use ::pueue::message::*;
@ -119,8 +121,10 @@ impl TaskHandler {
};
// Spawn the actual subprocess
let spawn_result = Command::new("sh")
.arg("-c")
let spawn_result = Command::new(if cfg!(windows) { "cmd" } else { "sh" })
// Windows: Tell cmd to output everything using unicode.
.args(if cfg!(windows) { Some("/U") } else { None })
.arg(if cfg!(windows) { "/C" } else { "-c" })
.arg(&task.command)
.current_dir(&task.path)
.stdin(Stdio::piped())
@ -258,6 +262,7 @@ impl TaskHandler {
}
/// Send a signal to a unix process
#[cfg(not(windows))]
fn send_signal(&mut self, id: usize, signal: Signal) -> Result<bool, nix::Error> {
if let Some(child) = self.children.get(&id) {
debug!("Sending signal {} to {}", signal, id);
@ -319,12 +324,19 @@ impl TaskHandler {
return;
}
}
match self.send_signal(id, Signal::SIGCONT) {
Err(err) => warn!("Failed starting task {}: {:?}", id, err),
Ok(success) => {
if success {
let mut state = self.state.lock().unwrap();
state.change_status(id, TaskStatus::Running);
#[cfg(windows)]
{
warn!("Failed starting task {}: not supported on windows.", id);
}
#[cfg(not(windows))]
{
match self.send_signal(id, Signal::SIGCONT) {
Err(err) => warn!("Failed starting task {}: {:?}", id, err),
Ok(success) => {
if success {
let mut state = self.state.lock().unwrap();
state.change_status(id, TaskStatus::Running);
}
}
}
}
@ -359,12 +371,19 @@ impl TaskHandler {
if !self.children.contains_key(&id) {
return;
}
match self.send_signal(id, Signal::SIGSTOP) {
Err(err) => info!("Failed pausing task {}: {:?}", id, err),
Ok(success) => {
if success {
let mut state = self.state.lock().unwrap();
state.change_status(id, TaskStatus::Paused);
#[cfg(windows)]
{
info!("Failed pausing task {}: not supported on windows.", id);
}
#[cfg(not(windows))]
{
match self.send_signal(id, Signal::SIGSTOP) {
Err(err) => info!("Failed pausing task {}: {:?}", id, err),
Ok(success) => {
if success {
let mut state = self.state.lock().unwrap();
state.change_status(id, TaskStatus::Paused);
}
}
}
}

View file

@ -1,5 +1,7 @@
use ::anyhow::Result;
use ::byteorder::{LittleEndian, ReadBytesExt};
use ::log::error;
use ::std::borrow::Cow;
use ::std::fs::{remove_file, File};
use ::std::io::prelude::*;
use ::std::path::{Path, PathBuf};
@ -32,6 +34,30 @@ pub fn get_log_file_handles(task_id: usize, settings: &Settings) -> Result<(File
Ok((stdout, stderr))
}
fn command_data_to_text(mut data: &[u8]) -> Cow<str> {
if cfg!(windows) {
// On windows we run the command using "cmd" with a flag that makes it output Unicode (UTF16).
let is_odd = data.len() % 2 == 1;
let mut buffer = Vec::with_capacity(data.len() / 2 + if is_odd { 1 } else { 0 });
type CmdUtf16Endian = LittleEndian;
while data.len() > 1 {
buffer.push(data.read_u16::<CmdUtf16Endian>().unwrap());
}
if is_odd {
let extra = [*data.last().unwrap(), 0];
let mut extra = &extra as &[u8];
buffer.push(extra.read_u16::<CmdUtf16Endian>().unwrap());
}
Cow::from(String::from_utf16_lossy(&buffer))
} else {
String::from_utf8_lossy(data)
}
}
/// Return the content of temporary stdout and stderr files for a task
pub fn read_log_files(task_id: usize, settings: &Settings) -> Result<(String, String)> {
let (mut stdout_handle, mut stderr_handle) = get_log_file_handles(task_id, settings)?;
@ -41,8 +67,8 @@ pub fn read_log_files(task_id: usize, settings: &Settings) -> Result<(String, St
stdout_handle.read_to_end(&mut stdout_buffer)?;
stderr_handle.read_to_end(&mut stderr_buffer)?;
let stdout = String::from_utf8_lossy(&stdout_buffer);
let stderr = String::from_utf8_lossy(&stderr_buffer);
let stdout = command_data_to_text(&stdout_buffer);
let stderr = command_data_to_text(&stderr_buffer);
Ok((stdout.to_string(), stderr.to_string()))
}

View file

@ -153,3 +153,32 @@ fn default_pueue_path() -> Result<String> {
|v| Ok(v.to_string()),
)
}
#[cfg(target_os = "windows")]
fn default_config_path() -> Result<PathBuf> {
Ok(get_home_dir()?.join("pueue.yml"))
}
#[cfg(target_os = "windows")]
fn get_config_paths() -> Result<Vec<PathBuf>> {
Ok(vec![
// Windows Terminal stores its config file in the "AppData/Local" directory.
dirs::data_local_dir()
.ok_or(anyhow!("Couldn't resolve app data directory"))?
.join("pueue/pueue.yml"),
default_config_path()?,
Path::new("./pueue.yml").to_path_buf(),
])
}
#[cfg(target_os = "windows")]
fn default_pueue_path() -> Result<String> {
// Use local data directory since this data doesn't need to be synced.
let path = dirs::data_local_dir()
.ok_or(anyhow!("Couldn't resolve app data directory"))?
.join("pueue");
path.to_str().map_or_else(
|| Err(anyhow!("Failed to parse log path (Weird characters?)")),
|v| Ok(v.to_string()),
)
}