From f3ea2b59084cf04f0caaa02896d8bc271f29e2b3 Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Thu, 12 Aug 2021 13:05:29 -0400 Subject: [PATCH 01/24] Add sysinfo package. Signed-off-by: Gene Johnston --- zowex/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/zowex/Cargo.toml b/zowex/Cargo.toml index 7a66c17fda..8046cbc54d 100644 --- a/zowex/Cargo.toml +++ b/zowex/Cargo.toml @@ -8,3 +8,4 @@ edition = "2018" [dependencies] rpassword = "5.0" +sysinfo = "0.20.0" From 9027a8534f11dd76b3765a76384477ec9d0fa73f Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Thu, 12 Aug 2021 13:06:34 -0400 Subject: [PATCH 02/24] Add sysinfo package. Signed-off-by: Gene Johnston --- zowex/Cargo.lock | 170 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 168 insertions(+), 2 deletions(-) diff --git a/zowex/Cargo.lock b/zowex/Cargo.lock index 1d6c7fbaba..1640748e9d 100644 --- a/zowex/Cargo.lock +++ b/zowex/Cargo.lock @@ -1,10 +1,154 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "core-foundation-sys" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" + +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" -version = "0.2.82" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765" + +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] + +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + +[[package]] +name = "rayon" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] [[package]] name = "rpassword" @@ -16,6 +160,27 @@ dependencies = [ "winapi", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "sysinfo" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0af066e6272f2175c1783cfc2ebf3e2d8dfe2c182b00677fdeccbf8291af83fb" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "libc", + "ntapi", + "once_cell", + "rayon", + "winapi", +] + [[package]] name = "winapi" version = "0.3.9" @@ -43,4 +208,5 @@ name = "zowex" version = "0.2.1" dependencies = [ "rpassword", + "sysinfo", ] From ceec64624a97ab94f28a3b03565bc0f2f605708b Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Thu, 12 Aug 2021 13:07:44 -0400 Subject: [PATCH 03/24] When we cannot connect to daemon, check if daemon is running. Signed-off-by: Gene Johnston --- zowex/src/main.rs | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/zowex/src/main.rs b/zowex/src/main.rs index 3f743e4356..c7cda6c9cf 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -20,6 +20,10 @@ use std::net::Shutdown; use std::net::TcpStream; use std::str; +extern crate sysinfo; +use sysinfo::{ProcessExt, System, SystemExt}; + + // NOTE(Kelosky): these sync with imperative header values const X_ZOWE_DAEMON_HEADERS: &str = "x-zowe-daemon-headers"; const X_ZOWE_DAEMON_EXIT: &str = "x-zowe-daemon-exit"; @@ -32,6 +36,8 @@ const DEFAULT_PORT: i32 = 4000; const X_ZOWE_DAEMON_REPLY: &str = "x-zowe-daemon-reply:"; +const CANNOT_CONNECT_TO_RUNNING_DAEMON_EXIT_CODE: i32 = 100; + // TODO(Kelosky): performance tests, `time for i in {1..10}; do zowe -h >/dev/null; done` // 0.8225 zowex vs 1.6961 zowe average over 10 run sample = .8736 sec faster on linux @@ -72,7 +78,19 @@ fn run_zowe_command(mut args: String, port_string: &str) -> std::io::Result<()> let mut daemon_host = "127.0.0.1:".to_owned(); daemon_host.push_str(&port_string); - let mut stream = TcpStream::connect(daemon_host).unwrap(); + let conn_result = TcpStream::connect(daemon_host); + if conn_result.is_err() { + // when we cannot connect, check if daemon is running + if is_daemon_running() { + println!("Unable to connect to a running Zowe daemon."); + std::process::exit(CANNOT_CONNECT_TO_RUNNING_DAEMON_EXIT_CODE); + } else { + println!("The daemon is NOT running, so we will start it."); + std::process::exit(666); // zzz + } + } + + let mut stream = conn_result.unwrap(); stream.write(_resp).unwrap(); // write it let mut stream_clone = stream.try_clone().expect("clone failed"); @@ -261,6 +279,28 @@ fn get_beg(buf: &str) -> Vec { return parts; } +// Is the zowe daemon currently running? +fn is_daemon_running() -> bool { + let mut sys = System::new_all(); + sys.refresh_all(); + for (pid, process) in sys.processes() { + if process.name().to_lowercase().contains("node") && + process.cmd()[1].to_lowercase().contains("@zowe") && + process.cmd()[1].to_lowercase().contains("cli") && + process.cmd()[2].to_lowercase() == "--daemon" + { + /* We print the daemon info, because we only check if the daemon + * is running when we cannot connect to it, and we are about to + * terminate with an error. This info may help diagnose the problem. + */ + println!("The Zowe daemon is running:"); + println!("pid={} name={} cmd={:?}", pid, process.name(), process.cmd()); + return true; + } + } + return false; +} + // // Unit tests // From 8042e39ece77bec8c75440d2dd19093375f686e2 Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Thu, 12 Aug 2021 18:57:39 -0400 Subject: [PATCH 04/24] Add module pathsearch. Signed-off-by: Gene Johnston --- zowex/Cargo.lock | 17 +++++++++++++++++ zowex/Cargo.toml | 1 + 2 files changed, 18 insertions(+) diff --git a/zowex/Cargo.lock b/zowex/Cargo.lock index 1640748e9d..6a9cf894eb 100644 --- a/zowex/Cargo.lock +++ b/zowex/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "anyhow" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486" + [[package]] name = "autocfg" version = "1.0.1" @@ -125,6 +131,16 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +[[package]] +name = "pathsearch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da983bc5e582ab17179c190b4b66c7d76c5943a69c6d34df2a2b6bf8a2977b05" +dependencies = [ + "anyhow", + "libc", +] + [[package]] name = "rayon" version = "1.5.1" @@ -207,6 +223,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" name = "zowex" version = "0.2.1" dependencies = [ + "pathsearch", "rpassword", "sysinfo", ] diff --git a/zowex/Cargo.toml b/zowex/Cargo.toml index 8046cbc54d..bc696a599a 100644 --- a/zowex/Cargo.toml +++ b/zowex/Cargo.toml @@ -7,5 +7,6 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +pathsearch = "0.2.0" rpassword = "5.0" sysinfo = "0.20.0" From c5a2a1870861516ce3a5323540012546ec6ac896 Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Thu, 12 Aug 2021 18:58:13 -0400 Subject: [PATCH 05/24] Add get_nodejs_zowe_path. Signed-off-by: Gene Johnston --- zowex/src/main.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/zowex/src/main.rs b/zowex/src/main.rs index c7cda6c9cf..e600ff1a88 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -8,11 +8,16 @@ * Copyright Contributors to the Zowe Project. * */ + +extern crate pathsearch; +use pathsearch::PathSearcher; + extern crate rpassword; use rpassword::read_password; use std::collections::HashMap; use std::env; +use std::ffi::OsString; use std::io::prelude::*; use std::io::BufReader; use std::io::{self, Write}; @@ -37,6 +42,8 @@ const DEFAULT_PORT: i32 = 4000; const X_ZOWE_DAEMON_REPLY: &str = "x-zowe-daemon-reply:"; const CANNOT_CONNECT_TO_RUNNING_DAEMON_EXIT_CODE: i32 = 100; +const CANNOT_GET_MY_PATH_EXIT_CODE: i32 = 101; +const NO_NODEJS_ZOWE_ON_PATH_EXIT_CODE: i32 = 102; // TODO(Kelosky): performance tests, `time for i in {1..10}; do zowe -h >/dev/null; done` // 0.8225 zowex vs 1.6961 zowe average over 10 run sample = .8736 sec faster on linux @@ -85,7 +92,9 @@ fn run_zowe_command(mut args: String, port_string: &str) -> std::io::Result<()> println!("Unable to connect to a running Zowe daemon."); std::process::exit(CANNOT_CONNECT_TO_RUNNING_DAEMON_EXIT_CODE); } else { - println!("The daemon is NOT running, so we will start it."); + println!("The Zowe daemon is NOT running, so we will start it."); + let njs_zowe_path = get_nodejs_zowe_path(); + println!("run_zowe_command: zzz: returning njs_zowe_path = {}", njs_zowe_path); std::process::exit(666); // zzz } } @@ -279,6 +288,51 @@ fn get_beg(buf: &str) -> Vec { return parts; } +// Get the file path to the command that runs the NodeJS version of Zowe +fn get_nodejs_zowe_path() -> String { + // get the path name to my own zowe rust executable + let my_exe_result = env::current_exe(); + if my_exe_result.is_err() { + println!("Unable to get path to my own executable. Terminating."); + std::process::exit(CANNOT_GET_MY_PATH_EXIT_CODE); + } + let my_exe_path_buf = my_exe_result.unwrap(); + let my_exe_path = my_exe_path_buf.to_string_lossy(); + + // we want a program file name that would execute a 'zowe' command + let mut zowe_file = "zowe"; + if env::consts::OS == "windows" { + zowe_file = "zowe.cmd"; + } + + // find every program in our path that would execute a 'zowe' command + const NOT_FOUND: &str = "notFound"; + let mut njs_zowe_path: String = NOT_FOUND.to_string(); + let path = env::var_os("PATH"); + let path_ext = env::var_os("PATHEXT"); + for njs_zowe_path_buf in PathSearcher::new( + zowe_file, + path.as_ref().map(OsString::as_os_str), + path_ext.as_ref().map(OsString::as_os_str), + ) { + njs_zowe_path = njs_zowe_path_buf.to_string_lossy().to_string(); + if njs_zowe_path.to_lowercase().eq(&my_exe_path.to_lowercase()) { + // We do not want our own rust executable. Keep searching. + njs_zowe_path = NOT_FOUND.to_string(); + continue; + } + + // use the first zowe command on our path that is not our own executable + break; + } + if njs_zowe_path == NOT_FOUND { + println!("Could not find a NodeJS zowe command on your path."); + println!("Cannot launch Zowe in daemon mode. Terminating."); + std::process::exit(NO_NODEJS_ZOWE_ON_PATH_EXIT_CODE); + } + return njs_zowe_path; +} + // Is the zowe daemon currently running? fn is_daemon_running() -> bool { let mut sys = System::new_all(); From def78fb8babb15f368148818188fa2db60fde0f0 Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Mon, 16 Aug 2021 17:42:06 -0400 Subject: [PATCH 06/24] Add start_daemon function. Make five connection attempts. Signed-off-by: Gene Johnston --- zowex/src/main.rs | 120 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 97 insertions(+), 23 deletions(-) diff --git a/zowex/src/main.rs b/zowex/src/main.rs index e600ff1a88..7d88b55153 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -9,12 +9,6 @@ * */ -extern crate pathsearch; -use pathsearch::PathSearcher; - -extern crate rpassword; -use rpassword::read_password; - use std::collections::HashMap; use std::env; use std::ffi::OsString; @@ -23,7 +17,16 @@ use std::io::BufReader; use std::io::{self, Write}; use std::net::Shutdown; use std::net::TcpStream; +use std::process::{Command}; use std::str; +use std::thread; +use std::time::Duration; + +extern crate pathsearch; +use pathsearch::PathSearcher; + +extern crate rpassword; +use rpassword::read_password; extern crate sysinfo; use sysinfo::{ProcessExt, System, SystemExt}; @@ -44,6 +47,8 @@ const X_ZOWE_DAEMON_REPLY: &str = "x-zowe-daemon-reply:"; const CANNOT_CONNECT_TO_RUNNING_DAEMON_EXIT_CODE: i32 = 100; const CANNOT_GET_MY_PATH_EXIT_CODE: i32 = 101; const NO_NODEJS_ZOWE_ON_PATH_EXIT_CODE: i32 = 102; +const CANNOT_START_DAEMON_EXIT_CODE: i32 = 103; +const DEAMON_NOT_RUNNING_AFTER_START_EXIT_CODE: i32 = 104; // TODO(Kelosky): performance tests, `time for i in {1..10}; do zowe -h >/dev/null; done` // 0.8225 zowex vs 1.6961 zowe average over 10 run sample = .8736 sec faster on linux @@ -82,24 +87,49 @@ fn run_zowe_command(mut args: String, port_string: &str) -> std::io::Result<()> _resp = b" "; } - let mut daemon_host = "127.0.0.1:".to_owned(); - daemon_host.push_str(&port_string); - - let conn_result = TcpStream::connect(daemon_host); - if conn_result.is_err() { - // when we cannot connect, check if daemon is running - if is_daemon_running() { - println!("Unable to connect to a running Zowe daemon."); + /* Attempt to make a TCP connection to the daemon. + * Iterate to enable a slow system to start the daemon. + */ + let daemon_host = format!("{}:{}", "127.0.0.1", port_string); + let mut conn_attempt = 1; + let mut we_started_daemon = false; + let mut daemon_cmd_to_show: String = "No value was set".to_string(); + let mut stream = loop { + let conn_result = TcpStream::connect(&daemon_host); + if let Ok(good_stream) = conn_result { + // We made our connection. Break with the actual stram value + break good_stream; + } + if is_daemon_running() == false { + if conn_attempt == 1 { + // start the daemon and continue trying to connect + let njs_zowe_path = get_nodejs_zowe_path(); + we_started_daemon = true; + daemon_cmd_to_show = start_daemon(&njs_zowe_path); + } else { + if we_started_daemon { + println!("This background Zowe process that we started is not running:\n {}\nTerminating.", + daemon_cmd_to_show + ); + std::process::exit(DEAMON_NOT_RUNNING_AFTER_START_EXIT_CODE); + } + } + } + if conn_attempt == 5 { + println!("Unable to connect to Zowe background process. Terminating after {} attempts", + conn_attempt + ); std::process::exit(CANNOT_CONNECT_TO_RUNNING_DAEMON_EXIT_CODE); - } else { - println!("The Zowe daemon is NOT running, so we will start it."); - let njs_zowe_path = get_nodejs_zowe_path(); - println!("run_zowe_command: zzz: returning njs_zowe_path = {}", njs_zowe_path); - std::process::exit(666); // zzz } - } - let mut stream = conn_result.unwrap(); + // pause between attempts to connect + thread::sleep(Duration::from_secs(3)); + if conn_attempt > 1 { + println!("Attempting to connect again ..."); + } + conn_attempt = conn_attempt + 1; + }; + stream.write(_resp).unwrap(); // write it let mut stream_clone = stream.try_clone().expect("clone failed"); @@ -327,7 +357,7 @@ fn get_nodejs_zowe_path() -> String { } if njs_zowe_path == NOT_FOUND { println!("Could not find a NodeJS zowe command on your path."); - println!("Cannot launch Zowe in daemon mode. Terminating."); + println!("Cannot launch Zowe background process. Terminating."); std::process::exit(NO_NODEJS_ZOWE_ON_PATH_EXIT_CODE); } return njs_zowe_path; @@ -347,7 +377,7 @@ fn is_daemon_running() -> bool { * is running when we cannot connect to it, and we are about to * terminate with an error. This info may help diagnose the problem. */ - println!("The Zowe daemon is running:"); + println!("The backgound Zowe process is running:"); println!("pid={} name={} cmd={:?}", pid, process.name(), process.cmd()); return true; } @@ -355,6 +385,50 @@ fn is_daemon_running() -> bool { return false; } +/** + * Start the zowe daemon. + * @param njs_zowe_path + * Full path to the NodeJS zowe command. + * @returns + * The command that was used to start the daemon (for display purposes). + */ +fn start_daemon(njs_zowe_path: &str) -> String { + println!("Starting a background process to increase performance ..."); + + // set OS-specific options + let shell_cmd; + let cmd_args; + if env::consts::OS == "windows" { + // Anything other than an empty title in the start command fails. + shell_cmd = "cmd"; + cmd_args = vec!["/C", "start", "", "/MIN", njs_zowe_path, "--daemon"]; + /* todo: The technique below has NO window, but it causes double output. + Maybe .stdout(Stdio::null()) could help, but in other cases, it also had problems. + shell_cmd = "cmd"; + cmd_args = vec!["/C", njs_zowe_path, "--daemon", "&&", "exit"]; + */ + } else { + shell_cmd = "sh"; + cmd_args = vec!["-c", njs_zowe_path, "--daemon"]; + } + + // record the command that we run (for display purposes) + let mut daemon_cmd_to_show: String = (&shell_cmd).to_string(); + for next_arg in cmd_args.iter() { + daemon_cmd_to_show.push_str(" "); + daemon_cmd_to_show.push_str(next_arg); + } + + // spawn the zowe daemon process and do not wait for termination + let new_proc = Command::new(shell_cmd).args(&cmd_args[..]).spawn(); + if new_proc.is_err() { + println!("Error = {:?}", new_proc); + println!("Failed to start the following process.\n {}\nTerminating.", daemon_cmd_to_show); + std::process::exit(CANNOT_START_DAEMON_EXIT_CODE); + } + return daemon_cmd_to_show; +} + // // Unit tests // From 8b25e59fd8e08e322ad20d18146655776ed1fdb1 Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Thu, 19 Aug 2021 13:42:55 -0400 Subject: [PATCH 07/24] Make executable name zowe. Update version. Signed-off-by: Gene Johnston --- zowex/Cargo.lock | 4 ++-- zowex/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/zowex/Cargo.lock b/zowex/Cargo.lock index 6a9cf894eb..5645e9bfe7 100644 --- a/zowex/Cargo.lock +++ b/zowex/Cargo.lock @@ -220,8 +220,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "zowex" -version = "0.2.1" +name = "zowe" +version = "0.3.0" dependencies = [ "pathsearch", "rpassword", diff --git a/zowex/Cargo.toml b/zowex/Cargo.toml index bc696a599a..1d89b8e66c 100644 --- a/zowex/Cargo.toml +++ b/zowex/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "zowex" -version = "0.2.1" +name = "zowe" +version = "0.3.0" authors = ["Zowe Project"] edition = "2018" From dd6ac32d6ada6c4b2ad33f48baea0dc389e5a8de Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Thu, 19 Aug 2021 19:40:20 -0400 Subject: [PATCH 08/24] Remove duplicated host. Add process information on connection failure. Signed-off-by: Gene Johnston --- zowex/src/main.rs | 83 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 26 deletions(-) diff --git a/zowex/src/main.rs b/zowex/src/main.rs index 7d88b55153..b0a3a93a0a 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -50,6 +50,13 @@ const NO_NODEJS_ZOWE_ON_PATH_EXIT_CODE: i32 = 102; const CANNOT_START_DAEMON_EXIT_CODE: i32 = 103; const DEAMON_NOT_RUNNING_AFTER_START_EXIT_CODE: i32 = 104; +struct DaemonProcInfo { + is_running: bool, + name: String, + pid: String, + cmd: String +} + // TODO(Kelosky): performance tests, `time for i in {1..10}; do zowe -h >/dev/null; done` // 0.8225 zowex vs 1.6961 zowe average over 10 run sample = .8736 sec faster on linux @@ -65,18 +72,14 @@ fn main() -> std::io::Result<()> { let mut _args: Vec = env::args().collect(); _args.drain(..1); // remove first (exe name) - let port_string = get_port_string(); - let mut daemon_host = "127.0.0.1:".to_owned(); - daemon_host.push_str(&port_string); - let args = _args.join(" "); - run_zowe_command(args, &port_string).unwrap(); + run_zowe_command(args).unwrap(); Ok(()) } -fn run_zowe_command(mut args: String, port_string: &str) -> std::io::Result<()> { +fn run_zowe_command(mut args: String) -> std::io::Result<()> { args.push_str(" --dcd "); let path = env::current_dir()?; args.push_str(path.to_str().unwrap()); @@ -87,20 +90,29 @@ fn run_zowe_command(mut args: String, port_string: &str) -> std::io::Result<()> _resp = b" "; } + // form our host, port, and connection strings + let daemon_host = "127.0.0.1".to_owned(); + let port_string = get_port_string(); + let host_port_conn_str = format!("{}:{}", daemon_host, port_string); + /* Attempt to make a TCP connection to the daemon. * Iterate to enable a slow system to start the daemon. */ - let daemon_host = format!("{}:{}", "127.0.0.1", port_string); let mut conn_attempt = 1; let mut we_started_daemon = false; let mut daemon_cmd_to_show: String = "No value was set".to_string(); let mut stream = loop { - let conn_result = TcpStream::connect(&daemon_host); + let conn_result = TcpStream::connect(&host_port_conn_str); if let Ok(good_stream) = conn_result { // We made our connection. Break with the actual stram value break good_stream; } - if is_daemon_running() == false { + + // determine if daemon is running + let daemon_proc_info = is_daemon_running(); + + // when not running, start it. + if daemon_proc_info.is_running == false { if conn_attempt == 1 { // start the daemon and continue trying to connect let njs_zowe_path = get_nodejs_zowe_path(); @@ -108,24 +120,29 @@ fn run_zowe_command(mut args: String, port_string: &str) -> std::io::Result<()> daemon_cmd_to_show = start_daemon(&njs_zowe_path); } else { if we_started_daemon { - println!("This background Zowe process that we started is not running:\n {}\nTerminating.", + println!("The Zowe daemon that we started is not running on host = {} with port = {}.", + daemon_host, port_string + ); + println!("Command used to start the Zowe daemon was:\n {}\nTerminating.", daemon_cmd_to_show ); std::process::exit(DEAMON_NOT_RUNNING_AFTER_START_EXIT_CODE); } } } + if conn_attempt == 5 { - println!("Unable to connect to Zowe background process. Terminating after {} attempts", - conn_attempt + println!("\nUnable to connect to Zowe daemon with name = {} and pid = {} on host = {} and port = {}.", + daemon_proc_info.name, daemon_proc_info.pid, daemon_host, port_string ); - std::process::exit(CANNOT_CONNECT_TO_RUNNING_DAEMON_EXIT_CODE); + println!("Command = {}\nTerminating after maximum retries.", daemon_proc_info.cmd); + std::process::exit(CANNOT_CONNECT_TO_RUNNING_DAEMON_EXIT_CODE); } // pause between attempts to connect thread::sleep(Duration::from_secs(3)); - if conn_attempt > 1 { - println!("Attempting to connect again ..."); + if conn_attempt == 1 && we_started_daemon == false || conn_attempt > 1 { + println!("Attempting to connect to Zowe daemon again ..."); } conn_attempt = conn_attempt + 1; }; @@ -357,14 +374,18 @@ fn get_nodejs_zowe_path() -> String { } if njs_zowe_path == NOT_FOUND { println!("Could not find a NodeJS zowe command on your path."); - println!("Cannot launch Zowe background process. Terminating."); + println!("Cannot launch Zowe daemon. Terminating."); std::process::exit(NO_NODEJS_ZOWE_ON_PATH_EXIT_CODE); } return njs_zowe_path; } -// Is the zowe daemon currently running? -fn is_daemon_running() -> bool { +/** + * Is the zowe daemon currently running? + * @returns A structure that indicates if the daemon is running, and if so + * properties about that running process. + */ +fn is_daemon_running() -> DaemonProcInfo { let mut sys = System::new_all(); sys.refresh_all(); for (pid, process) in sys.processes() { @@ -373,16 +394,26 @@ fn is_daemon_running() -> bool { process.cmd()[1].to_lowercase().contains("cli") && process.cmd()[2].to_lowercase() == "--daemon" { - /* We print the daemon info, because we only check if the daemon - * is running when we cannot connect to it, and we are about to - * terminate with an error. This info may help diagnose the problem. - */ - println!("The backgound Zowe process is running:"); - println!("pid={} name={} cmd={:?}", pid, process.name(), process.cmd()); - return true; + // convert the process command from a vector to a string + let mut proc_cmd: String = "".to_string(); + for cmd_part in process.cmd() { + proc_cmd.push_str(cmd_part); + proc_cmd.push(' '); + } + return DaemonProcInfo { + is_running: true, + name: process.name().to_string(), + pid: pid.to_string(), + cmd: proc_cmd + }; } } - return false; + return DaemonProcInfo { + is_running: false, + name: "no name".to_string(), + pid: "no pid".to_string(), + cmd: "no cmd".to_string() + }; } /** From bd5411ee9ee3ca736f66e68f122d07d3df49f26a Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Mon, 23 Aug 2021 11:28:03 -0400 Subject: [PATCH 09/24] Alter how the daemon is launched for Linux. Signed-off-by: Gene Johnston --- zowex/src/main.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/zowex/src/main.rs b/zowex/src/main.rs index b0a3a93a0a..8a3de1299d 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -17,7 +17,7 @@ use std::io::BufReader; use std::io::{self, Write}; use std::net::Shutdown; use std::net::TcpStream; -use std::process::{Command}; +use std::process::{Command, Stdio}; use std::str; use std::thread; use std::time::Duration; @@ -429,18 +429,28 @@ fn start_daemon(njs_zowe_path: &str) -> String { // set OS-specific options let shell_cmd; let cmd_args; + let stdout_val; + let stderr_val; + let mut njs_daemon_cmd_linux: String = njs_zowe_path.to_string(); if env::consts::OS == "windows" { // Anything other than an empty title in the start command fails. shell_cmd = "cmd"; cmd_args = vec!["/C", "start", "", "/MIN", njs_zowe_path, "--daemon"]; + stdout_val = Stdio::inherit(); + stderr_val = Stdio::inherit(); + /* todo: The technique below has NO window, but it causes double output. Maybe .stdout(Stdio::null()) could help, but in other cases, it also had problems. shell_cmd = "cmd"; cmd_args = vec!["/C", njs_zowe_path, "--daemon", "&&", "exit"]; */ } else { + // the whole command must be supplied as one parm to "sh -c" + njs_daemon_cmd_linux.push_str(" --daemon &"); shell_cmd = "sh"; - cmd_args = vec!["-c", njs_zowe_path, "--daemon"]; + cmd_args = vec!["-c", &njs_daemon_cmd_linux]; + stdout_val = Stdio::null(); + stderr_val = Stdio::null(); } // record the command that we run (for display purposes) @@ -451,7 +461,11 @@ fn start_daemon(njs_zowe_path: &str) -> String { } // spawn the zowe daemon process and do not wait for termination - let new_proc = Command::new(shell_cmd).args(&cmd_args[..]).spawn(); + let new_proc = Command::new(shell_cmd) + .args(&cmd_args[..]) + .stdout(stdout_val) + .stderr(stderr_val) + .spawn(); if new_proc.is_err() { println!("Error = {:?}", new_proc); println!("Failed to start the following process.\n {}\nTerminating.", daemon_cmd_to_show); From f63159c4f2742da386e255277f7b97de82e3a238 Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Mon, 23 Aug 2021 19:14:12 -0400 Subject: [PATCH 10/24] Run Win command with no color (no escape chars). Signed-off-by: Gene Johnston --- zowex/src/main.rs | 82 +++++++++++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 28 deletions(-) diff --git a/zowex/src/main.rs b/zowex/src/main.rs index 8a3de1299d..e5c525b6dc 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -100,7 +100,7 @@ fn run_zowe_command(mut args: String) -> std::io::Result<()> { */ let mut conn_attempt = 1; let mut we_started_daemon = false; - let mut daemon_cmd_to_show: String = "No value was set".to_string(); + let mut cmd_to_show: String = "No value was set".to_string(); let mut stream = loop { let conn_result = TcpStream::connect(&host_port_conn_str); if let Ok(good_stream) = conn_result { @@ -117,14 +117,14 @@ fn run_zowe_command(mut args: String) -> std::io::Result<()> { // start the daemon and continue trying to connect let njs_zowe_path = get_nodejs_zowe_path(); we_started_daemon = true; - daemon_cmd_to_show = start_daemon(&njs_zowe_path); + cmd_to_show = start_daemon(&njs_zowe_path); } else { if we_started_daemon { println!("The Zowe daemon that we started is not running on host = {} with port = {}.", daemon_host, port_string ); println!("Command used to start the Zowe daemon was:\n {}\nTerminating.", - daemon_cmd_to_show + cmd_to_show ); std::process::exit(DEAMON_NOT_RUNNING_AFTER_START_EXIT_CODE); } @@ -427,51 +427,77 @@ fn start_daemon(njs_zowe_path: &str) -> String { println!("Starting a background process to increase performance ..."); // set OS-specific options - let shell_cmd; - let cmd_args; + let shell_pgm; + let cmd_to_run; let stdout_val; let stderr_val; - let mut njs_daemon_cmd_linux: String = njs_zowe_path.to_string(); + + // must be declared outside of the "if" scope. Thanks a lot Rust! + let mut zowe_cmd_linux: String = "".to_string(); + if env::consts::OS == "windows" { - // Anything other than an empty title in the start command fails. - shell_cmd = "cmd"; - cmd_args = vec!["/C", "start", "", "/MIN", njs_zowe_path, "--daemon"]; - stdout_val = Stdio::inherit(); - stderr_val = Stdio::inherit(); - - /* todo: The technique below has NO window, but it causes double output. - Maybe .stdout(Stdio::null()) could help, but in other cases, it also had problems. - shell_cmd = "cmd"; - cmd_args = vec!["/C", njs_zowe_path, "--daemon", "&&", "exit"]; + shell_pgm = "cmd"; + cmd_to_run = vec!["/C", njs_zowe_path, "--daemon", "&&", "exit"]; + /* + The following has no window, no color and no escape characters. + The 'exit' command hangs. You must type exit AND control-C, or + click the X button on your original command window. + When you do terminate your command window, the daemon automatically terminates. + cmd_to_run = vec!["/C", njs_zowe_path, "--daemon", "&&", "exit"]; + + The following has no window, no color, no escape characters + The 'exit' command hangs. You must click the X button on your original command window. + When you do terminate your command window, the daemon automatically terminates. + Anything other than an empty title in the start command fails. + cmd_to_run = vec!["/C", "start", "", "/b", njs_zowe_path, "--daemon"]; + + The following launches a minimized window on the task bar. + CMD.exe and PowerShell show escape characters for color. + All shells look fine in ConEmu. + You must separately exit the daemon window. + Anything other than an empty title in the start command fails. + cmd_to_run = vec!["/C", "start", "", "/MIN", njs_zowe_path, "--daemon"]; + */ + + /* + If you inherit stdout, CMD and PowerShell show escape characters for color. + If use use null, you get no color. + stdout_val = Stdio::inherit(); + stderr_val = Stdio::inherit(); */ + stdout_val = Stdio::null(); + stderr_val = Stdio::null(); } else { - // the whole command must be supplied as one parm to "sh -c" - njs_daemon_cmd_linux.push_str(" --daemon &"); - shell_cmd = "sh"; - cmd_args = vec!["-c", &njs_daemon_cmd_linux]; + // the whole command must be supplied as one parm to "sh -c" command. + zowe_cmd_linux.push_str(njs_zowe_path); + zowe_cmd_linux.push_str(" --daemon &"); + shell_pgm = "sh"; + cmd_to_run = vec!["-c", &zowe_cmd_linux]; + + // If you inherit stdout, you get double output. If use use null, you get no color. stdout_val = Stdio::null(); stderr_val = Stdio::null(); } // record the command that we run (for display purposes) - let mut daemon_cmd_to_show: String = (&shell_cmd).to_string(); - for next_arg in cmd_args.iter() { - daemon_cmd_to_show.push_str(" "); - daemon_cmd_to_show.push_str(next_arg); + let mut cmd_to_show: String = (&shell_pgm).to_string(); + for next_arg in cmd_to_run.iter() { + cmd_to_show.push_str(" "); + cmd_to_show.push_str(next_arg); } // spawn the zowe daemon process and do not wait for termination - let new_proc = Command::new(shell_cmd) - .args(&cmd_args[..]) + let new_proc = Command::new(shell_pgm) + .args(cmd_to_run) .stdout(stdout_val) .stderr(stderr_val) .spawn(); if new_proc.is_err() { println!("Error = {:?}", new_proc); - println!("Failed to start the following process.\n {}\nTerminating.", daemon_cmd_to_show); + println!("Failed to start the following process.\n {}\nTerminating.", cmd_to_show); std::process::exit(CANNOT_START_DAEMON_EXIT_CODE); } - return daemon_cmd_to_show; + return cmd_to_show; } // From be51377a7bce9e1987a132f88e30f8d89399017a Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Wed, 1 Sep 2021 17:33:20 -0400 Subject: [PATCH 11/24] Run deamon or classic zowe based on env variable. Signed-off-by: Gene Johnston --- zowex/src/main.rs | 86 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 82 insertions(+), 4 deletions(-) diff --git a/zowex/src/main.rs b/zowex/src/main.rs index e5c525b6dc..8e90bebd7a 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -72,11 +72,16 @@ fn main() -> std::io::Result<()> { let mut _args: Vec = env::args().collect(); _args.drain(..1); // remove first (exe name) - let args = _args.join(" "); - - run_zowe_command(args).unwrap(); + if user_wants_daemon() { + // interact with the daemon + let args = _args.join(" "); + run_zowe_command(args).unwrap(); + return Ok(()) + } - Ok(()) + // user wants to run classic NodeJS zowe + run_classic_zowe(&mut _args); + return Ok(()); } fn run_zowe_command(mut args: String) -> std::io::Result<()> { @@ -416,6 +421,79 @@ fn is_daemon_running() -> DaemonProcInfo { }; } +/** + * Should we use daemon mode? The user controls this with an environment variable. + * @returns true or false. + */ +fn user_wants_daemon() -> bool { + const DAEMON_ENV_VAR_NM: &str = "ZOWE_USE_DAEMON"; + let env_var_val; + match env::var(DAEMON_ENV_VAR_NM) { + Ok(val) => env_var_val = val, + Err(_e) => env_var_val = "NoDaemon".to_string(), + } + + if env_var_val.to_lowercase() == "true" || env_var_val.to_lowercase() == "yes" { + return true + } + return false; +} + +/** + * Run the classic NodeJS zowe command. + * @param cmd_line_args + * The user-supplied command line arguments to the zowe command. + */ +fn run_classic_zowe(cmd_line_args: &mut Vec) { + let njs_zowe_path = get_nodejs_zowe_path(); + + // set OS-specific options + let shell_pgm; + let shell_flag; + if env::consts::OS == "windows" { + shell_pgm = "cmd"; + shell_flag = "/C"; + } else { + shell_pgm = "sh"; + shell_flag = "-c"; + } + + // Form the command that we must launch. + let mut pgm_args = vec![]; + pgm_args.push(shell_flag.to_string()); + pgm_args.push(njs_zowe_path.to_string()); + + // form the command that we show in an error message. + let mut cmd_to_show: String = (&shell_pgm).to_string(); + cmd_to_show.push_str(" "); + cmd_to_show.push_str(shell_flag); + cmd_to_show.push_str(" "); + cmd_to_show.push_str(&njs_zowe_path); + + // add user-supplied arguments to both commands + for next_arg in cmd_line_args.iter() { + cmd_to_show.push_str(" "); + cmd_to_show.push_str(next_arg); + pgm_args.push(next_arg.to_string()); + } + + /* We cannot use pgm_args after any error due to rust's stupid string ownership. + * The following statement can show individual arguments more precisely for debugging. + * println!("\nrun_classic_zowe: shell_pgm = {} pgm_args = {:?}", shell_pgm, pgm_args); + */ + + // launch classic zowe and wait for it to complete. + let new_proc = Command::new(shell_pgm) + .args(pgm_args) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .output(); + if new_proc.is_err() { + println!("Error = {:?}", new_proc); + println!("Failed to run the following command:\n {}", cmd_to_show); + } +} + /** * Start the zowe daemon. * @param njs_zowe_path From fed3c97bbcbf218793146cfe188238d54969b2a5 Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Thu, 2 Sep 2021 18:09:24 -0400 Subject: [PATCH 12/24] Alter how we launch classic zowe on Linux. Signed-off-by: Gene Johnston --- zowex/src/main.rs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/zowex/src/main.rs b/zowex/src/main.rs index 8e90bebd7a..5d08dd3945 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -447,30 +447,21 @@ fn user_wants_daemon() -> bool { fn run_classic_zowe(cmd_line_args: &mut Vec) { let njs_zowe_path = get_nodejs_zowe_path(); - // set OS-specific options + // The command to launch varies by OS let shell_pgm; - let shell_flag; + let mut pgm_args = vec![]; if env::consts::OS == "windows" { shell_pgm = "cmd"; - shell_flag = "/C"; + pgm_args.push("/C".to_string()); + pgm_args.push(njs_zowe_path.to_string()); } else { - shell_pgm = "sh"; - shell_flag = "-c"; + shell_pgm = &njs_zowe_path; } - // Form the command that we must launch. - let mut pgm_args = vec![]; - pgm_args.push(shell_flag.to_string()); - pgm_args.push(njs_zowe_path.to_string()); - // form the command that we show in an error message. let mut cmd_to_show: String = (&shell_pgm).to_string(); - cmd_to_show.push_str(" "); - cmd_to_show.push_str(shell_flag); - cmd_to_show.push_str(" "); - cmd_to_show.push_str(&njs_zowe_path); - // add user-supplied arguments to both commands + // add user-supplied arguments to both the command to show and to launch for next_arg in cmd_line_args.iter() { cmd_to_show.push_str(" "); cmd_to_show.push_str(next_arg); From 47748a23a119d720540891346d90a51828d39a59 Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Fri, 3 Sep 2021 19:00:55 -0400 Subject: [PATCH 13/24] Turn off color when starting daemon on Windows. Signed-off-by: Gene Johnston --- zowex/src/main.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/zowex/src/main.rs b/zowex/src/main.rs index 5d08dd3945..cb840d732d 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -536,6 +536,12 @@ fn start_daemon(njs_zowe_path: &str) -> String { */ stdout_val = Stdio::null(); stderr_val = Stdio::null(); + + /* Windows CMD and Powershell terminal windows show escape characters + * instead of colors in daemon-mode. A more elegant solution may exist, + * but for now we just turn off color in daemon mode on Windows. + */ + env::set_var("FORCE_COLOR", "0"); } else { // the whole command must be supplied as one parm to "sh -c" command. zowe_cmd_linux.push_str(njs_zowe_path); From 762051eb7fc36abef36d958460b0a8c344a88798 Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Fri, 24 Sep 2021 16:05:35 -0400 Subject: [PATCH 14/24] Add daemon-mode changelog entries. Signed-off-by: Gene Johnston --- packages/cli/CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 68c37dcb69..3eb49e10b5 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to the Zowe CLI package will be documented in this file. +## Recent Changes + +- Daemon mode updates: + - Enhancements: + - Renamed the platform-specific executable from zowex to zowe, so that existing zowe commands used from the command line or in scripts do not have to change when running in daemon mode. + - Use an environment variable named ZOWE_USE_DAEMON with a value of "yes" to determine if zowe commands should run in daemon mode. + - Automatically launch the background daemon when one is not running. + - The daemon no longer has its own visible window, making it much more daemon-like. + - Bugfixs: + - Eliminate the display of escape characters when colors are displayed while running in daemon mode. [#938](https://github.com/zowe/zowe-cli/issues/938). Currently accomplished by not displaying colors in daemon mode. + - Command-line arguments that contain spaces no longer require extra quotes or escapes. [#978](https://github.com/zowe/zowe-cli/issues/978) + ## `7.0.0-next.202109032014` - Enhancement: Log in to API ML to obtain token value instead of prompting for it in `config secure` command. From 4c2c2cd5d3ca4088cb657ccbe1da152e5635cf4c Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Fri, 24 Sep 2021 18:45:47 -0400 Subject: [PATCH 15/24] Add quotes to args with spaces in cmd sent to daemon. Return exit code of NodeJS zowe, when not using daemon. Use simpler program launching techniques. Add exit codes for failing to launch programs. Signed-off-by: Gene Johnston --- zowex/src/main.rs | 305 ++++++++++++++++++++++++++-------------------- 1 file changed, 170 insertions(+), 135 deletions(-) diff --git a/zowex/src/main.rs b/zowex/src/main.rs index cb840d732d..fcef891996 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -44,11 +44,13 @@ const DEFAULT_PORT: i32 = 4000; const X_ZOWE_DAEMON_REPLY: &str = "x-zowe-daemon-reply:"; -const CANNOT_CONNECT_TO_RUNNING_DAEMON_EXIT_CODE: i32 = 100; -const CANNOT_GET_MY_PATH_EXIT_CODE: i32 = 101; -const NO_NODEJS_ZOWE_ON_PATH_EXIT_CODE: i32 = 102; -const CANNOT_START_DAEMON_EXIT_CODE: i32 = 103; -const DEAMON_NOT_RUNNING_AFTER_START_EXIT_CODE: i32 = 104; +const EXIT_CODE_CANNOT_CONNECT_TO_RUNNING_DAEMON: i32 = 100; +const EXIT_CODE_CANNOT_GET_MY_PATH: i32 = 101; +const EXIT_CODE_NO_NODEJS_ZOWE_ON_PATH: i32 = 102; +const EXIT_CODE_CANNOT_START_DAEMON: i32 = 103; +const EXIT_CODE_DEAMON_NOT_RUNNING_AFTER_START: i32 = 104; +const EXIT_CODE_DAEMON_FAILED_TO_RUN_CMD: i32 = 105; +const EXIT_CODE_FAILED_TO_RUN_NODEJS_CMD: i32 = 106; struct DaemonProcInfo { is_running: bool, @@ -70,21 +72,83 @@ struct DaemonProcInfo { fn main() -> std::io::Result<()> { // turn args into vector let mut _args: Vec = env::args().collect(); + _args.drain(..1); // remove first (exe name) + let cmd_result: Result; if user_wants_daemon() { - // interact with the daemon - let args = _args.join(" "); - run_zowe_command(args).unwrap(); - return Ok(()) + /* Convert our vector of arguments into a single string of arguments + * for transmittal to the daemon. + */ + let arg_string = arg_vec_to_string(_args); + + // send command to the daemon + match run_daemon_command(arg_string) { + Ok(_value) => { + /* todo: Change run_daemon_command() to return an exit code. + * We can then process its cmd_result return value just like + * we do for run_nodejs_command(). As it stands now, our + * exit code is always zero, regardless of the exit code of + * the command run by the daemon. + */ + cmd_result = Ok(0); + }, + Err(error) => { + println!("The daemon failed to run your command due to this error:\n{}", error); + cmd_result = Ok(EXIT_CODE_DAEMON_FAILED_TO_RUN_CMD); + } + } + } else { + // user wants to run classic NodeJS zowe + cmd_result = run_nodejs_command(&mut _args); + } + + // stupid rust does not enable main() to return an exit code. This is the work-around. + match cmd_result { + Ok(value) => { + std::process::exit(value); + }, + Err(error) => { + println!("NodeJS zowe failed to run your command due to this error:\n{}", error); + std::process::exit(EXIT_CODE_FAILED_TO_RUN_NODEJS_CMD); + } + } +} + +/** + * Convert a vector of command line arguments into a single string of arguments. + * @param cmd_line_args + * The user-supplied command line arguments to the zowe command. + * Each argument is in its own vector element. + * @returns + * A String containing all of the command line arguments. + */ +fn arg_vec_to_string(arg_vec: Vec) -> String { + let mut arg_string = String::new(); + let mut arg_count = 1; + for next_arg in arg_vec.iter() { + if arg_count > 1 { + arg_string.push(' '); + } + + /* An argument that contains a space must be enclosed in double quotes + * when it is placed into a single argument string. + */ + if next_arg.contains(' ') { + arg_string.push('"'); + arg_string.push_str(next_arg); + arg_string.push('"'); + } else { + arg_string.push_str(next_arg); + } + + arg_count = arg_count + 1; } - // user wants to run classic NodeJS zowe - run_classic_zowe(&mut _args); - return Ok(()); + return arg_string; } -fn run_zowe_command(mut args: String) -> std::io::Result<()> { +fn run_daemon_command(mut args: String) -> std::io::Result<()> { args.push_str(" --dcd "); let path = env::current_dir()?; args.push_str(path.to_str().unwrap()); @@ -105,11 +169,11 @@ fn run_zowe_command(mut args: String) -> std::io::Result<()> { */ let mut conn_attempt = 1; let mut we_started_daemon = false; - let mut cmd_to_show: String = "No value was set".to_string(); + let mut cmd_to_show: String = String::new(); let mut stream = loop { let conn_result = TcpStream::connect(&host_port_conn_str); if let Ok(good_stream) = conn_result { - // We made our connection. Break with the actual stram value + // We made our connection. Break with the actual stream value break good_stream; } @@ -123,7 +187,7 @@ fn run_zowe_command(mut args: String) -> std::io::Result<()> { let njs_zowe_path = get_nodejs_zowe_path(); we_started_daemon = true; cmd_to_show = start_daemon(&njs_zowe_path); - } else { + } else { if we_started_daemon { println!("The Zowe daemon that we started is not running on host = {} with port = {}.", daemon_host, port_string @@ -131,7 +195,7 @@ fn run_zowe_command(mut args: String) -> std::io::Result<()> { println!("Command used to start the Zowe daemon was:\n {}\nTerminating.", cmd_to_show ); - std::process::exit(DEAMON_NOT_RUNNING_AFTER_START_EXIT_CODE); + std::process::exit(EXIT_CODE_DEAMON_NOT_RUNNING_AFTER_START); } } } @@ -141,7 +205,7 @@ fn run_zowe_command(mut args: String) -> std::io::Result<()> { daemon_proc_info.name, daemon_proc_info.pid, daemon_host, port_string ); println!("Command = {}\nTerminating after maximum retries.", daemon_proc_info.cmd); - std::process::exit(CANNOT_CONNECT_TO_RUNNING_DAEMON_EXIT_CODE); + std::process::exit(EXIT_CODE_CANNOT_CONNECT_TO_RUNNING_DAEMON); } // pause between attempts to connect @@ -342,19 +406,22 @@ fn get_beg(buf: &str) -> Vec { // Get the file path to the command that runs the NodeJS version of Zowe fn get_nodejs_zowe_path() -> String { - // get the path name to my own zowe rust executable + /* On Linux/Mac both our executable and shell script are named 'zowe'. + * First get the path name to my own zowe rust executable. + */ let my_exe_result = env::current_exe(); if my_exe_result.is_err() { println!("Unable to get path to my own executable. Terminating."); - std::process::exit(CANNOT_GET_MY_PATH_EXIT_CODE); + std::process::exit(EXIT_CODE_CANNOT_GET_MY_PATH); } let my_exe_path_buf = my_exe_result.unwrap(); let my_exe_path = my_exe_path_buf.to_string_lossy(); - // we want a program file name that would execute a 'zowe' command - let mut zowe_file = "zowe"; + let zowe_cmd; if env::consts::OS == "windows" { - zowe_file = "zowe.cmd"; + zowe_cmd = "zowe.cmd"; + } else { + zowe_cmd = "zowe"; } // find every program in our path that would execute a 'zowe' command @@ -363,7 +430,7 @@ fn get_nodejs_zowe_path() -> String { let path = env::var_os("PATH"); let path_ext = env::var_os("PATHEXT"); for njs_zowe_path_buf in PathSearcher::new( - zowe_file, + zowe_cmd, path.as_ref().map(OsString::as_os_str), path_ext.as_ref().map(OsString::as_os_str), ) { @@ -374,14 +441,15 @@ fn get_nodejs_zowe_path() -> String { continue; } - // use the first zowe command on our path that is not our own executable + // use the first 'zowe' command on our path that is not our own executable break; } if njs_zowe_path == NOT_FOUND { println!("Could not find a NodeJS zowe command on your path."); - println!("Cannot launch Zowe daemon. Terminating."); - std::process::exit(NO_NODEJS_ZOWE_ON_PATH_EXIT_CODE); + println!("Will not be able to run Zowe commands. Terminating."); + std::process::exit(EXIT_CODE_NO_NODEJS_ZOWE_ON_PATH); } + return njs_zowe_path; } @@ -400,7 +468,7 @@ fn is_daemon_running() -> DaemonProcInfo { process.cmd()[2].to_lowercase() == "--daemon" { // convert the process command from a vector to a string - let mut proc_cmd: String = "".to_string(); + let mut proc_cmd: String = String::new(); for cmd_part in process.cmd() { proc_cmd.push_str(cmd_part); proc_cmd.push(' '); @@ -443,135 +511,102 @@ fn user_wants_daemon() -> bool { * Run the classic NodeJS zowe command. * @param cmd_line_args * The user-supplied command line arguments to the zowe command. + * @returns + * Our error code when we fail to the NodeJS zowe. + * Otherwise, the exit code of the NodeJs zowe command. */ -fn run_classic_zowe(cmd_line_args: &mut Vec) { - let njs_zowe_path = get_nodejs_zowe_path(); - - // The command to launch varies by OS - let shell_pgm; - let mut pgm_args = vec![]; - if env::consts::OS == "windows" { - shell_pgm = "cmd"; - pgm_args.push("/C".to_string()); - pgm_args.push(njs_zowe_path.to_string()); - } else { - shell_pgm = &njs_zowe_path; - } +fn run_nodejs_command(cmd_line_args: &mut Vec) -> Result { + let njs_zowe_path = get_nodejs_zowe_path(); - // form the command that we show in an error message. - let mut cmd_to_show: String = (&shell_pgm).to_string(); - - // add user-supplied arguments to both the command to show and to launch - for next_arg in cmd_line_args.iter() { - cmd_to_show.push_str(" "); - cmd_to_show.push_str(next_arg); - pgm_args.push(next_arg.to_string()); - } - - /* We cannot use pgm_args after any error due to rust's stupid string ownership. - * The following statement can show individual arguments more precisely for debugging. - * println!("\nrun_classic_zowe: shell_pgm = {} pgm_args = {:?}", shell_pgm, pgm_args); - */ - - // launch classic zowe and wait for it to complete. - let new_proc = Command::new(shell_pgm) - .args(pgm_args) + // launch classic NodeJS zowe and wait for it to complete. + let exit_code: i32; + match Command::new(njs_zowe_path.to_owned()) + .args(cmd_line_args.to_owned()) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) - .output(); - if new_proc.is_err() { - println!("Error = {:?}", new_proc); - println!("Failed to run the following command:\n {}", cmd_to_show); - } + .output() + { + Ok(new_proc) => { + exit_code = new_proc.status.code().unwrap(); + }, + Err(error) => { + println!("Failed to run the following command:"); + println!(" Program = {}\n arguments = {:?}", njs_zowe_path, cmd_line_args); + println!("Due to this error:\n {}", error); + exit_code = EXIT_CODE_FAILED_TO_RUN_NODEJS_CMD; + } + }; + + return Ok(exit_code); } /** * Start the zowe daemon. + * * @param njs_zowe_path * Full path to the NodeJS zowe command. * @returns * The command that was used to start the daemon (for display purposes). + * + * Here are alternate programming options for implementing this function that have been tried. + * + * On windows: + * If we run cmd with vec!["/C", njs_zowe_path, "--daemon", "&&", "exit"] + * we get no window, no color, and no escape characters. + * The 'exit' command hangs. You must type exit AND control-C, or + * click the X button on your original command window. + * When you do terminate your command window, the daemon automatically terminates. + * + * If we run cmd with vec!["/C", "start", "", "/b", njs_zowe_path, "--daemon"]; + * we get no window, no color, and no escape characters. + * The 'exit' command hangs. You must click the X button on your original command window. + * When you do terminate your command window, the daemon automatically terminates. + * Anything other than an empty title in the start command fails. + * + * If we run cmd with vec!["/C", "start", "", "/MIN", njs_zowe_path, "--daemon"]; + * we launch a minimized window on the task bar. + * CMD.exe and PowerShell show escape characters for color. + * All shells look fine in ConEmu. + * You must separately exit the daemon window. + * Anything other than an empty title in the start command fails. + * + * If you use Stdio::inherit(), CMD and PowerShell show escape characters for color. + * If use use Stdio::null(), you get no color. Some commands still show color on windows, + * which produce escape characters. That is why we use the FORCE_COLOR=0 env variable on windows. + * + * On Linux: + * If you use Stdio::inherit(), you get double output. If use use Stdio::null(), you get no color. */ fn start_daemon(njs_zowe_path: &str) -> String { println!("Starting a background process to increase performance ..."); - // set OS-specific options - let shell_pgm; - let cmd_to_run; - let stdout_val; - let stderr_val; - - // must be declared outside of the "if" scope. Thanks a lot Rust! - let mut zowe_cmd_linux: String = "".to_string(); - if env::consts::OS == "windows" { - shell_pgm = "cmd"; - cmd_to_run = vec!["/C", njs_zowe_path, "--daemon", "&&", "exit"]; - /* - The following has no window, no color and no escape characters. - The 'exit' command hangs. You must type exit AND control-C, or - click the X button on your original command window. - When you do terminate your command window, the daemon automatically terminates. - cmd_to_run = vec!["/C", njs_zowe_path, "--daemon", "&&", "exit"]; - - The following has no window, no color, no escape characters - The 'exit' command hangs. You must click the X button on your original command window. - When you do terminate your command window, the daemon automatically terminates. - Anything other than an empty title in the start command fails. - cmd_to_run = vec!["/C", "start", "", "/b", njs_zowe_path, "--daemon"]; - - The following launches a minimized window on the task bar. - CMD.exe and PowerShell show escape characters for color. - All shells look fine in ConEmu. - You must separately exit the daemon window. - Anything other than an empty title in the start command fails. - cmd_to_run = vec!["/C", "start", "", "/MIN", njs_zowe_path, "--daemon"]; - */ - - /* - If you inherit stdout, CMD and PowerShell show escape characters for color. - If use use null, you get no color. - stdout_val = Stdio::inherit(); - stderr_val = Stdio::inherit(); - */ - stdout_val = Stdio::null(); - stderr_val = Stdio::null(); - /* Windows CMD and Powershell terminal windows show escape characters - * instead of colors in daemon-mode. A more elegant solution may exist, - * but for now we just turn off color in daemon mode on Windows. - */ + * instead of colors in daemon-mode. A more elegant solution may exist, + * but for now we just turn off color in daemon mode on Windows. + */ env::set_var("FORCE_COLOR", "0"); - } else { - // the whole command must be supplied as one parm to "sh -c" command. - zowe_cmd_linux.push_str(njs_zowe_path); - zowe_cmd_linux.push_str(" --daemon &"); - shell_pgm = "sh"; - cmd_to_run = vec!["-c", &zowe_cmd_linux]; - - // If you inherit stdout, you get double output. If use use null, you get no color. - stdout_val = Stdio::null(); - stderr_val = Stdio::null(); } - // record the command that we run (for display purposes) - let mut cmd_to_show: String = (&shell_pgm).to_string(); - for next_arg in cmd_to_run.iter() { - cmd_to_show.push_str(" "); - cmd_to_show.push_str(next_arg); - } + let daemon_arg = "--daemon"; + match Command::new(njs_zowe_path.to_owned()) + .arg(daemon_arg) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + { + Ok(_unused) => { /* nothing to do */ }, + Err(error) => { + println!("Failed to start the following process:\n {} {}", njs_zowe_path, daemon_arg); + println!("Due to this error:\n {}", error); + std::process::exit(EXIT_CODE_CANNOT_START_DAEMON); + } + }; - // spawn the zowe daemon process and do not wait for termination - let new_proc = Command::new(shell_pgm) - .args(cmd_to_run) - .stdout(stdout_val) - .stderr(stderr_val) - .spawn(); - if new_proc.is_err() { - println!("Error = {:?}", new_proc); - println!("Failed to start the following process.\n {}\nTerminating.", cmd_to_show); - std::process::exit(CANNOT_START_DAEMON_EXIT_CODE); - } + // return the command that we run (for display purposes) + let mut cmd_to_show: String = njs_zowe_path.to_owned(); + cmd_to_show.push_str(" "); + cmd_to_show.push_str(daemon_arg); return cmd_to_show; } From e2e45d2f5a5d1413306c67354eec5645d83cd473 Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Thu, 21 Oct 2021 15:50:17 -0400 Subject: [PATCH 16/24] Fix typo in change log. Signed-off-by: Gene Johnston --- packages/cli/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index f154231fca..0930dbd9c4 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -10,7 +10,7 @@ All notable changes to the Zowe CLI package will be documented in this file. - Use an environment variable named ZOWE_USE_DAEMON with a value of "yes" to determine if zowe commands should run in daemon mode. - Automatically launch the background daemon when one is not running. - The daemon no longer has its own visible window, making it much more daemon-like. - - Bugfixs: + - Bug fixes: - Eliminate the display of escape characters when colors are displayed while running in daemon mode. [#938](https://github.com/zowe/zowe-cli/issues/938). Currently accomplished by not displaying colors in daemon mode. - Command-line arguments that contain spaces no longer require extra quotes or escapes. [#978](https://github.com/zowe/zowe-cli/issues/978) From f8108667899594e378d479f20e76ea2d03847c1f Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Mon, 1 Nov 2021 12:15:30 -0400 Subject: [PATCH 17/24] Use daemon mode by default. Env var turns it off Signed-off-by: Gene Johnston --- zowex/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zowex/src/main.rs b/zowex/src/main.rs index fcef891996..319ee04d9c 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -501,10 +501,10 @@ fn user_wants_daemon() -> bool { Err(_e) => env_var_val = "NoDaemon".to_string(), } - if env_var_val.to_lowercase() == "true" || env_var_val.to_lowercase() == "yes" { - return true + if env_var_val.to_lowercase() == "false" || env_var_val.to_lowercase() == "no" { + return false } - return false; + return true; } /** From 560131cfd65ed3497a3ec3fbbd40983c0d1210cd Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Mon, 1 Nov 2021 16:18:28 -0400 Subject: [PATCH 18/24] Update check_changelog_action to v1. Signed-off-by: Gene Johnston --- .github/workflows/changelog.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index 6bfc9527a5..6eda3ad4fc 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -19,7 +19,7 @@ jobs: - name: Check Changelog Updated id: checkchangelogupdated if: ${{ contains( github.event.pull_request.labels.*.name, 'no-changelog') != true }} - uses: awharn/check_changelog_action@v0.0.3 + uses: awharn/check_changelog_action@v1 with: header: '## Recent Changes' file: 'CHANGELOG.md' From b85201c1ec925166c42a37ed3641acdd4e54a3a4 Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Mon, 1 Nov 2021 16:19:32 -0400 Subject: [PATCH 19/24] Publish under the name zowe instead of zowex. Signed-off-by: Gene Johnston --- .github/workflows/rust-cli-publish.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/rust-cli-publish.yml b/.github/workflows/rust-cli-publish.yml index 3561ed0f8c..4d4aec5953 100644 --- a/.github/workflows/rust-cli-publish.yml +++ b/.github/workflows/rust-cli-publish.yml @@ -87,7 +87,7 @@ jobs: - name: Create Archive run: | cd target/release - tar -cvzf zowex.tgz zowex + tar -cvzf zowe.tgz zowe - name: Upload Release Asset id: upload-release-asset @@ -96,8 +96,8 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.get_upload_url.outputs.upload_url }} - asset_path: target/release/zowex.tgz - asset_name: zowex-linux.tgz + asset_path: target/release/zowe.tgz + asset_name: zowe-linux.tgz asset_content_type: application/octet-stream @@ -126,7 +126,7 @@ jobs: - name: Create Archive run: | cd target/release - tar -cvzf zowex.tgz zowex + tar -cvzf zowe.tgz zowe - name: Upload Release Asset id: upload-release-asset @@ -135,8 +135,8 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.get_upload_url.outputs.upload_url }} - asset_path: target/release/zowex.tgz - asset_name: zowex-macos.tgz + asset_path: target/release/zowe.tgz + asset_name: zowe-macos.tgz asset_content_type: application/octet-stream @@ -165,7 +165,7 @@ jobs: - name: Create Archive run: | cd target/release - tar -cvzf zowex.tgz zowex.exe + tar -cvzf zowe.tgz zowe.exe - name: Upload Release Asset id: upload-release-asset @@ -174,6 +174,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.get_upload_url.outputs.upload_url }} - asset_path: target\release\zowex.tgz - asset_name: zowex-windows.tgz + asset_path: target\release\zowe.tgz + asset_name: zowe-windows.tgz asset_content_type: application/octet-stream From d76312cd1c29fd109473e0c386eba128ffd8a6f8 Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Mon, 1 Nov 2021 16:20:45 -0400 Subject: [PATCH 20/24] Document ZOWE_USE_DAEMON with "no" instead of yes Signed-off-by: Gene Johnston --- packages/cli/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 0930dbd9c4..68ee27ce63 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -7,9 +7,9 @@ All notable changes to the Zowe CLI package will be documented in this file. - Daemon mode updates: - Enhancements: - Renamed the platform-specific executable from zowex to zowe, so that existing zowe commands used from the command line or in scripts do not have to change when running in daemon mode. - - Use an environment variable named ZOWE_USE_DAEMON with a value of "yes" to determine if zowe commands should run in daemon mode. - Automatically launch the background daemon when one is not running. - The daemon no longer has its own visible window, making it much more daemon-like. + - An environment variable named ZOWE_USE_DAEMON can be set to "no" to prevent the use of the daemon. The command is passed to the traditional zowe-CLI command. Thus, you can temporarily use the traditional Zowe CLI command to correct some display limitations (like displaying colors). - Bug fixes: - Eliminate the display of escape characters when colors are displayed while running in daemon mode. [#938](https://github.com/zowe/zowe-cli/issues/938). Currently accomplished by not displaying colors in daemon mode. - Command-line arguments that contain spaces no longer require extra quotes or escapes. [#978](https://github.com/zowe/zowe-cli/issues/978) From 4e46abd42f3dcbb319bfd4de19ed0148e552da9c Mon Sep 17 00:00:00 2001 From: zFernand0 Date: Tue, 2 Nov 2021 17:24:22 +0000 Subject: [PATCH 21/24] Add artifacts to each Rust CI build Signed-off-by: zFernand0 --- .github/workflows/rust-cli.yml | 84 +++++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 6 deletions(-) diff --git a/.github/workflows/rust-cli.yml b/.github/workflows/rust-cli.yml index 962538f95b..fb907bd2d4 100644 --- a/.github/workflows/rust-cli.yml +++ b/.github/workflows/rust-cli.yml @@ -3,22 +3,94 @@ name: Rust CLI CI on: push: branches-ignore: - - "master" - - "next" - paths: "zowex/**" + - "master" + - "next" + paths: + - "zowex/**" + - '.github/workflows/rust-cli*.yml' pull_request: paths: "zowex/**" jobs: - build: - + build-linux: + name: Build Linux runs-on: ubuntu-latest + # Need to build in container with old version of GLIBC to support RHEL 7 + # https://kobzol.github.io/rust/ci/2021/05/07/building-rust-binaries-in-ci-that-work-with-older-glibc.html + container: quay.io/pypa/manylinux2014_x86_64 + steps: + - uses: actions/checkout@v2 + + - name: Install Rust toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + + - name: Build + run: cargo build --verbose --manifest-path=zowex/Cargo.toml + + - name: Create Archive + run: | + cd zowex/target/debug + tar -cvzf zowe.tgz zowe + + - name: Archive Results + id: upload + uses: actions/upload-artifact@v2 + with: + name: zowe-linux.tgz + path: zowex/target/debug/zowe.tgz + + - name: Run tests + run: cargo test --verbose --manifest-path=zowex/Cargo.toml + + build-macos: + name: Build MacOS + runs-on: macos-latest steps: - uses: actions/checkout@v2 - name: Build run: cargo build --verbose --manifest-path=zowex/Cargo.toml + - name: Create Archive + run: | + cd zowex/target/debug + tar -cvzf zowe.tgz zowe + + - name: Archive Results + id: upload + uses: actions/upload-artifact@v2 + with: + name: zowe-macos.tgz + path: zowex/target/debug/zowe.tgz + + - name: Run tests + run: cargo test --verbose --manifest-path=zowex/Cargo.toml + + build-windows: + name: Build Windows + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + + - name: Build + run: cargo build --verbose --manifest-path=zowex/Cargo.toml + + - name: Create Archive + run: | + cd zowex/target/debug + tar -cvzf zowe.tgz zowe.exe + + - name: Archive Results + id: upload + uses: actions/upload-artifact@v2 + with: + name: zowe-windows.tgz + path: zowex/target/debug/zowe.tgz + - name: Run tests - run: cargo test --verbose --manifest-path=zowex/Cargo.toml \ No newline at end of file + run: cargo test --verbose --manifest-path=zowex/Cargo.toml From 6f67894b521e1e4187e41ac0f4cbc0e97a97724e Mon Sep 17 00:00:00 2001 From: Timothy Johnson Date: Thu, 4 Nov 2021 10:09:24 -0400 Subject: [PATCH 22/24] Bundle prebuilt daemon binaries in CLI package Signed-off-by: Timothy Johnson --- Jenkinsfile | 14 ++++++++++++++ jenkins/bundleDaemon.sh | 23 +++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 jenkins/bundleDaemon.sh diff --git a/Jenkinsfile b/Jenkinsfile index ef48241fe7..e8878d5154 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -168,6 +168,20 @@ node('zowe-jenkins-agent-dind') { header: "## Recent Changes" ) + pipeline.createStage( + name: "Bundle Daemon Binaries", + shouldExecute: { + return pipeline.protectedBranches.isProtected(BRANCH_NAME) + }, + timeout: [time: 10, unit: 'MINUTES'], + stage: { + def daemonVer = readProperties(file: "zowex/Cargo.toml").version + withCredentials([usernamePassword(credentialsId: 'zowe-robot-github', usernameVariable: 'USERNAME', passwordVariable: 'TOKEN')]) { + sh "bash jenkins/bundleDaemon.sh ${daemonVer} \"${USERNAME}:${TOKEN}\"" + } + } + ) + pipeline.createStage( name: "Bundle Keytar Binaries", shouldExecute: { diff --git a/jenkins/bundleDaemon.sh b/jenkins/bundleDaemon.sh new file mode 100644 index 0000000000..3d41d1a8c3 --- /dev/null +++ b/jenkins/bundleDaemon.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# Usage: bash bundleDaemon.sh [githubAuthHeader] +set -ex + +daemonVersion=$1 +githubAuthHeader=$2 + +until [[ $(curl -fs https://$githubAuthHeader@api.github.com/repos/zowe/zowe-cli/releases/tags/native-v$daemonVersion | + jq -r '.assets | length') = '3' ]]; do + echo "Waiting for Rust CLI Publish workflow to complete..." + sleep 30 +done + +cd "$(git rev-parse --show-toplevel)" +rm -rf prebuilds +mkdir prebuilds && cd prebuilds + +for platform in linux macos windows; do + curl -fsLOJ https://github.com/zowe/zowe-cli/releases/download/native-v$daemonVersion/zowe-$platform.tgz +done + +cd .. +mv prebuilds packages/cli/ From 039da7c0d1a7d0ccae8e6ccfc2d2f3f01b2078b9 Mon Sep 17 00:00:00 2001 From: Timothy Johnson Date: Thu, 4 Nov 2021 13:26:52 -0400 Subject: [PATCH 23/24] Use double equals as compare symbol in Bash Signed-off-by: Timothy Johnson --- jenkins/bundleDaemon.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jenkins/bundleDaemon.sh b/jenkins/bundleDaemon.sh index 3d41d1a8c3..1cf684e5be 100644 --- a/jenkins/bundleDaemon.sh +++ b/jenkins/bundleDaemon.sh @@ -6,7 +6,7 @@ daemonVersion=$1 githubAuthHeader=$2 until [[ $(curl -fs https://$githubAuthHeader@api.github.com/repos/zowe/zowe-cli/releases/tags/native-v$daemonVersion | - jq -r '.assets | length') = '3' ]]; do + jq -r '.assets | length') == "3" ]]; do echo "Waiting for Rust CLI Publish workflow to complete..." sleep 30 done From 3e288b0e518d4a37ed11347874cc410e96955023 Mon Sep 17 00:00:00 2001 From: Gene Johnston Date: Mon, 8 Nov 2021 17:16:26 -0500 Subject: [PATCH 24/24] Add 0 to list of values that can turn off daemon. Signed-off-by: Gene Johnston --- zowex/src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zowex/src/main.rs b/zowex/src/main.rs index 319ee04d9c..933a72d943 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -501,7 +501,9 @@ fn user_wants_daemon() -> bool { Err(_e) => env_var_val = "NoDaemon".to_string(), } - if env_var_val.to_lowercase() == "false" || env_var_val.to_lowercase() == "no" { + if env_var_val.to_lowercase() == "false" || env_var_val.to_lowercase() == "no" || + env_var_val == "0" + { return false } return true;