1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
//! # Overview //! //! This is a rust attribute-like proc macro which reduces the amount of code required to call shell commands and parse the results. //! //! It allows you to wrap a script in any language with strongly typed functions. The function's arguments are set as env variables and the result of the script is parsed either as a value or as an iterator. //! //! [![Crates.io](https://img.shields.io/crates/v/shellfn.svg)](https://crates.io/crates/shellfn) //! [![license](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/kbknapp/clap-rs/blob/master/LICENSE-MIT) //! [![Build Status](https://travis-ci.org/synek317/shellfn.svg?branch=master)](https://travis-ci.org/synek317/shellfn) //! //! [Documentation](https://docs.rs/shellfn/) //! //! [Repository](https://github.com/synek317/shellfn) //! //! ## Examples //! //! ### Basic //! //! ```rust //! use shellfn::shell; //! use std::error::Error; //! //! #[shell] //! fn list_modified(dir: &str) -> Result<impl Iterator<Item=String>, Box<Error>> { r#" //! cd $DIR //! git status | grep '^\s*modified:' | awk '{print $2}' //! "# } //! ``` //! //! ### Different interpreter //! //! ```rust //! use shellfn::shell; //! use std::error::Error; //! //! #[shell(cmd = "python -c")] //! fn pretty_json(json: &str, indent: u8, sort_keys: bool) -> Result<String, Box<Error>> { r#" //! import os, json //! //! input = os.environ['JSON'] //! indent = int(os.environ['INDENT']) //! sort_keys = os.environ['SORT_KEYS'] == 'true' //! obj = json.loads(input) //! //! print(json.dumps(obj, indent=indent, sort_keys=sort_keys)) //! "# } //! ``` //! //! ## Usage //! //! You can use the `#[shell]` attribute on functions that have: //! - a body containing only one expression - a string literal representing the script to execute //! - types that implement the `.to_string()` method //! - return a value that is either `void`, `T`, `Result<T, E>`, `impl Iterator<Item=T>`, `Result<impl Iterator<Item=T>>` or `Result<impl Iterator<Item=Result<T, E>>>` with constrains: //! ``` //! T: FromStr, //! <T as FromStr>::Err: StdError, //! E: From<shellfn::Error<<T as FromStr>::Err>>, //! ``` //! //! - ## Details //! //! The `#[shell]` attribute does the following: //! //! 1. Sets every argument as an env variable //! 2. Runs a shell command //! 3. Launches the command using `std::process::Command` //! 4. Depending on the return type, it may parse the output //! //! Most of the steps can be adjusted: //! - the default command is `bash -c`. You can change it using the `cmd` parameter: //! ```rust //! #[shell(cmd = "python -c")] //! ``` //! - by default, the script is added as the last argument. You can change it using the special variable `PROGRAM` in the `cmd` parameter: //! ```rust //! #[shell(cmd = "bash -c PROGRAM -i")] //! ``` //! - if the return type is not wrapping some part of the result in `Result`, you may decide to suppress panics by adding the `no_panic` flag: //! ```rust //! #[shell(no_panic)] //! ``` //! //! Following return types are currently recognized: //! //! | return type | flags | on parse fail | on error exit code | on spawn fail | notes | //! |-----------------------------------------------|----------|---------------|--------------------|---------------|-------| //! | | | - | panic | panic | | //! | | no_panic | - | nothing | nothing | | //! | T | | panic | panic | panic | 2 | //! | T | no_panic | panic | panic | panic | 1,2 | //! | Result<T, E> | | error | error | error | 2 | //! | Result<T, E> | no_panic | error | error | error | 1,2 | //! | impl Iterator<Item=T> | | panic | panic | panic | | //! | impl Iterator<Item=T> | no_panic | ignore errors | ignore errors | empty iter | 3 | //! | impl Iterator<Item=Result<T, E>> | | item error | panic | panic | 3 | //! | impl Iterator<Item=Result<T, E>> | no_panic | item error | ignored | empty iter | | //! | Result<impl Iterator<Item=T>, E> | | panic | ignored | error | | //! | Result<impl Iterator<Item=T>, E> | no_panic | ignore errors | ignored | error | | //! | Result<impl Iterator<Item=Result<T, E1>>, E2> | | item error | ignored | error | | //! | Result<impl Iterator<Item=Result<T, E1>>, E2> | no_panic | item error | ignored | error | 1 | //! //! Glossary: //! //! | action | meaning | //! |---------------|--------------------------------------------------------------------------| //! | panic | panics (.expect or panic!) | //! | nothing | consumes and ignores error (let _ = ...) | //! | error | returns error | //! | ignore errors | yields all successfuly parsed items, ignores parsing failures (flat_map) | //! | empty iter | returns empty iterator | //! | item error | when parsing fails, yields Err | //! | ignored | ignores exit code, behaves in the same way for exit code 0 and != 0 | //! //! Notes: //! //! 1. The `no_panic` attribute makes no difference //! 2. It reads all of stdout before producing any failures //! 3. It yields all items until it encounters an error or an exit code pub use shellfn_attribute::*; pub use shellfn_core::*;