nias-0.7.0/.cargo_vcs_info.json0000644000000001121373351175500120340ustar { "git": { "sha1": "065740213fc3d33a56a7a84e945300b86e447634" } } nias-0.7.0/.gitignore010064400017500001750000000000351364346175600126360ustar 00000000000000/target **/*.rs.bk Cargo.locknias-0.7.0/Cargo.toml0000644000000021761373351175500100460ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "nias" version = "0.7.0" authors = ["Swellaby "] exclude = [".coverage/**", ".testresults/**", ".azure-pipelines/**", ".dependabot/**", ".github/**", ".vscode/**", "scripts/**", ".editorconfig", ".gitattributes", ".rustfmt.toml", ".rusty-hook.toml", "azure-pipelines.yml", "kcov*/**", "**/*.gcda", "**/*.gcno", "tests/**"] description = "closure generator library" readme = "README.md" license = "MIT" repository = "https://github.com/swellaby/nias" [dependencies] [dev-dependencies.rusty-hook] version = "0.11.0" [badges.maintenance] status = "actively-developed" nias-0.7.0/Cargo.toml.orig010066400017500001750000000012241373351164400135300ustar 00000000000000[package] name = "nias" version = "0.7.0" authors = ["Swellaby "] description = "closure generator library" license = "MIT" repository = "https://github.com/swellaby/nias" readme = "README.md" edition = "2018" exclude = [ ".coverage/**", ".testresults/**", ".azure-pipelines/**", ".dependabot/**", ".github/**", ".vscode/**", "scripts/**", ".editorconfig", ".gitattributes", ".rustfmt.toml", ".rusty-hook.toml", "azure-pipelines.yml", "kcov*/**", "**/*.gcda", "**/*.gcno", "tests/**", ] [dependencies] [dev-dependencies] rusty-hook = "0.11.0" [badges] maintenance = { status = "actively-developed" } nias-0.7.0/LICENSE010064400017500001750000000020561364373754500116620ustar 00000000000000MIT License Copyright (c) 2019-2020 Swellaby Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. nias-0.7.0/README.md010064400017500001750000000035231364346175600121320ustar 00000000000000# nias Library for generating commonly used closures [![Version Badge][version-badge]][crate url] [![Downloads Badge][downloads-badge]][crate url] [![License Badge][license-badge]][crate url] [![Linux CI Badge][linux-ci-badge]][linux-ci-url] [![Mac CI Badge][mac-ci-badge]][mac-ci-url] [![Windows CI Badge][windows-ci-badge]][windows-ci-url] [![Test Results Badge][tests-badge]][tests-url] [![Coverage Badge][coverage-badge]][coverage-url] [version-badge]: https://img.shields.io/crates/v/nias?style=flat-square [license-badge]: https://img.shields.io/crates/l/nias?style=flat-square [downloads-badge]: https://img.shields.io/crates/d/nias?style=flat-square [crate url]: https://crates.io/crates/nias [linux-ci-badge]: https://img.shields.io/azure-devops/build/swellaby/opensource/105/master?label=linux%20build&style=flat-square [linux-ci-url]: https://dev.azure.com/swellaby/OpenSource/_build/latest?definitionId=105 [mac-ci-badge]: https://img.shields.io/azure-devops/build/swellaby/opensource/106/master?label=mac%20build&style=flat-square [mac-ci-url]: https://dev.azure.com/swellaby/OpenSource/_build/latest?definitionId=106 [windows-ci-badge]: https://img.shields.io/azure-devops/build/swellaby/opensource/107/master?label=windows%20build&style=flat-square [windows-ci-url]: https://dev.azure.com/swellaby/OpenSource/_build/latest?definitionId=107 [coverage-badge2]: https://img.shields.io/azure-devops/coverage/swellaby/opensource/105/master?style=flat-square [coverage-badge]: https://img.shields.io/badge/coverage-unknown-lightgrey?style=flat-square [coverage-url]: https://codecov.io/gh/swellaby/nias [tests-badge]: https://img.shields.io/azure-devops/tests/swellaby/opensource/105/master?label=unit%20tests&style=flat-square [tests-url]: https://dev.azure.com/swellaby/OpenSource/_build/latest?definitionId=105&view=ms.vss-test-web.build-test-results-tab nias-0.7.0/src/command.rs010066400017500001750000000043261373351164400134220ustar 00000000000000use std::collections::HashMap; use std::io::Result as IOResult; use std::process::{Command, ExitStatus, Output}; #[cfg(target_family = "unix")] const PROGRAM: &str = "sh"; #[cfg(target_family = "unix")] const SWITCH: &str = "-c"; #[cfg(target_family = "windows")] const PROGRAM: &str = "cmd"; #[cfg(target_family = "windows")] const SWITCH: &str = "/C"; fn handle_command_output(output: IOResult) -> Result, Option> { match output { Err(details) => panic!( "Command runner crashed in unrecoverable manner. Details: {}", details ), Ok(output) => { if output.status.success() { Ok(Some( String::from_utf8(output.stdout) .unwrap() .trim_end_matches('\n') .to_string(), )) } else { Err(Some(format!( "{}\n{}", String::from_utf8(output.stderr).unwrap(), String::from_utf8(output.stdout).unwrap(), ))) } } } } fn handle_streamed_command( exit_status: IOResult, ) -> Result, Option> { match exit_status { Err(details) => panic!( "Command runner crashed in unrecoverable manner. Details: {}", details ), Ok(status) if status.success() => Ok(None), Ok(_) => Err(None), } } #[allow(clippy::type_complexity)] pub fn get_command_runner() -> fn( cmd: &str, dir: Option<&str>, stream_io: bool, env_vars: Option<&HashMap>, ) -> Result, Option> { |cmd: &str, dir: Option<&str>, stream_io: bool, env_vars: Option<&HashMap>| { let mut command = Command::new(PROGRAM); command.current_dir(dir.unwrap_or(".")).args(&[SWITCH, cmd]); if let Some(ev) = env_vars { command.envs(ev); } if stream_io { handle_streamed_command(command.status()) } else { handle_command_output(command.output()) } } } #[cfg(test)] #[path = "command_test.rs"] mod command_tests; nias-0.7.0/src/command_test.rs010066400017500001750000000061241373351164400144570ustar 00000000000000use super::*; use std::process::ExitStatus; const RAW_STDOUT_OUTPUT: &str = "hello\nworld!\n\n"; const EXP_OUTPUT: &str = "hello\nworld!"; #[cfg(target_family = "windows")] fn get_exit_status(raw: u32) -> ExitStatus { use std::os::windows::process::ExitStatusExt; ExitStatus::from_raw(raw) } #[cfg(target_family = "unix")] fn get_exit_status(raw: u32) -> ExitStatus { use std::os::unix::process::ExitStatusExt; ExitStatus::from_raw(raw as i32) } #[cfg(test)] mod get_command_runner_tests { use super::get_command_runner; use std::collections::HashMap; #[test] fn returns_correct_closure() { fn validate( _run_command: fn( &str, Option<&str>, bool, Option<&HashMap>, ) -> Result, Option>, ) -> bool { true }; let command_runner = get_command_runner(); assert!(validate(command_runner)); } } #[cfg(test)] mod handle_command_output_tests { use super::*; use std::io::{Error, ErrorKind}; use std::process::Output; #[test] #[should_panic( expected = "Command runner crashed in unrecoverable manner. Details: crashed hard" )] fn should_panic_on_command_error() { let error_details = "crashed hard"; let error = Error::new(ErrorKind::Other, error_details); let _ = handle_command_output(Err(error)); } #[test] fn should_return_ok_with_stdout_on_command_success() { let output = Output { status: get_exit_status(0), stdout: Vec::from(RAW_STDOUT_OUTPUT.as_bytes()), stderr: Vec::new(), }; let result = handle_command_output(Ok(output)); assert_eq!(result.unwrap(), Some(String::from(EXP_OUTPUT))); } #[test] fn should_return_err_with_stdout_stderr_mix_on_command_failure() { let std_error = "utter failure\n"; let output = Output { status: get_exit_status(3), stdout: Vec::from(RAW_STDOUT_OUTPUT.as_bytes()), stderr: Vec::from(std_error.as_bytes()), }; let result = handle_command_output(Ok(output)); assert_eq!( result.unwrap_err(), Some(format!("{}\n{}", std_error, RAW_STDOUT_OUTPUT)) ); } } #[cfg(test)] mod handle_streamed_command_tests { use super::*; use std::io::{Error, ErrorKind}; #[test] #[should_panic(expected = "Command runner crashed in unrecoverable manner. Details: oops!")] fn should_panic_on_command_error() { let error_details = "oops!"; let error = Error::new(ErrorKind::Other, error_details); let _ = handle_streamed_command(Err(error)); } #[test] fn should_return_ok_on_command_success() { let result = handle_streamed_command(Ok(get_exit_status(0))); assert_eq!(result.unwrap(), None); } #[test] fn should_return_err_on_command_failure() { let result = handle_streamed_command(Ok(get_exit_status(3))); assert_eq!(result.unwrap_err(), None); } } nias-0.7.0/src/file_io.rs010064400017500001750000000046361364373724700134250ustar 00000000000000use std::fs::{remove_file, File}; use std::io::prelude::*; #[cfg(target_family = "unix")] use std::os::unix::fs::PermissionsExt; use std::path::{Path, PathBuf}; #[cfg(target_family = "unix")] fn create_file(path: PathBuf, make_executable: bool) -> Result { let file = match File::create(&path) { Ok(file) => file, Err(_) => return Err(()), }; if make_executable { let metadata = match file.metadata() { Ok(metadata) => metadata, Err(_) => return Err(()), }; let mut permissions = metadata.permissions(); permissions.set_mode(0o755); if std::fs::set_permissions(&path, permissions).is_err() { return Err(()); }; }; Ok(file) } #[cfg(target_family = "windows")] fn create_file(path: PathBuf, _make_executable: bool) -> Result { match File::create(&path) { Err(_) => Err(()), Ok(file) => Ok(file), } } pub fn get_file_writer( ) -> fn(file_path: &str, contents: &str, make_executable: bool) -> Result<(), String> { |file_path: &str, contents: &str, make_executable: bool| { let path = PathBuf::from(file_path); let mut file = match create_file(path, make_executable) { Ok(f) => f, Err(_) => return Err(format!("Failed to create file {}", file_path)), }; match file.write_all(contents.as_bytes()) { Ok(_) => Ok(()), Err(_) => Err(format!("Failed to write contents to {}", file_path)), } } } pub fn get_file_existence_checker() -> fn(file_path: &str) -> Result { |file_path: &str| Ok(Path::new(file_path).exists()) } pub fn get_file_reader() -> fn(file_path: &str) -> Result { |file_path: &str| { let mut file = match File::open(&Path::new(file_path)) { Err(_) => return Err(()), Ok(file) => file, }; let mut contents = String::new(); match file.read_to_string(&mut contents) { Err(_) => Err(()), Ok(_) => Ok(contents), } } } pub fn get_file_remover() -> fn(file_path: &str) -> Result<(), String> { |file_path: &str| match remove_file(file_path) { Ok(_) => Ok(()), Err(msg) => Err(format!( "Failed to remove file: {}. Error details: {}", file_path, msg )), } } #[cfg(test)] #[path = "file_io_test.rs"] mod file_io_tests; nias-0.7.0/src/file_io_test.rs010064400017500001750000000023211364346175600144500ustar 00000000000000use super::*; #[cfg(test)] mod get_file_writer_tests { use super::*; #[test] fn returns_correct_closure() { fn validate(_write_file: fn(&str, &str, bool) -> Result<(), String>) -> bool { true }; let writer = get_file_writer(); assert!(validate(writer)); } } #[cfg(test)] mod get_file_existence_checker_tests { use super::*; #[test] fn returns_correct_closure() { fn validate(_exists: fn(&str) -> Result) -> bool { true }; let file_exists = get_file_existence_checker(); assert!(validate(file_exists)); } } #[cfg(test)] mod get_file_reader_tests { use super::*; #[test] fn returns_correct_closure() { fn validate(_read: fn(&str) -> Result) -> bool { true }; let read_file = get_file_reader(); assert!(validate(read_file)); } } #[cfg(test)] mod get_file_remover_tests { use super::*; #[test] fn returns_correct_closure() { fn validate(_remove_file: fn(&str) -> Result<(), String>) -> bool { true }; let remover = get_file_remover(); assert!(validate(remover)); } } nias-0.7.0/src/lib.rs010064400017500001750000000001611364346175600125510ustar 00000000000000mod command; mod file_io; mod log; pub use crate::command::*; pub use crate::file_io::*; pub use crate::log::*; nias-0.7.0/src/log.rs010064400017500001750000000010061364346175600125630ustar 00000000000000use std::io::Write; fn log(writer: &mut W, message: &str) { writeln!(writer, "{}", message).unwrap_or_default(); } fn log_conditionally(writer: &mut W, message: &str, should_log: bool) { if should_log { log(writer, message); } } pub fn get_conditional_logger() -> fn(message: &str, should_log: bool) { |message: &str, should_log: bool| { log_conditionally(&mut std::io::stdout(), message, should_log); } } #[cfg(test)] #[path = "log_test.rs"] mod log_tests; nias-0.7.0/src/log_test.rs010064400017500001750000000023751373351111300136130ustar 00000000000000use super::*; #[cfg(test)] mod log_tests { use super::*; #[test] fn writes_to_buffer() { let mut writer = Vec::new(); let message = "winning"; log(&mut writer, message); assert_eq!(&writer[..], "winning\n".as_bytes()); } } #[cfg(test)] mod log_conditionally_tests { use super::*; #[test] fn writes_to_buffer_when_should_log_true() { let mut writer = Vec::new(); let message = "test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out"; let exp = &format!("{}\n", message); log_conditionally(&mut writer, message, true); assert_eq!(&writer[..], exp.as_bytes()); } #[test] fn does_not_write_to_buffer_when_should_log_false() { let mut writer = Vec::new(); let message = "do not log me!!!"; log_conditionally(&mut writer, message, false); assert_eq!(&writer[..], "".as_bytes()); } } #[cfg(test)] mod get_conditional_logger_tests { use super::*; #[test] fn returns_correct_closure() { fn validate(_log_conditionally: fn(&str, bool)) -> bool { true }; let logger = get_conditional_logger(); logger("", false); assert!(validate(logger)); } }