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::*;