Skip to content

Commit 6296d95

Browse files
committed
Allow path/OsString variables being used directly
Use OsString for internal commands, and convert all Debug types into OsString by using std::any dynamic typing. Fixed #24.
1 parent 0ecd274 commit 6296d95

File tree

8 files changed

+151
-55
lines changed

8 files changed

+151
-55
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ let now = Instant::now();
5151
sudo bash -c "dd if=$file of=/dev/null bs=$block_size skip=$off count=$cnt 2>&1"
5252
| awk r#"/copied/{print $(NF-1) " " $NF}"#
5353
)
54-
.unwrap_or_else(|e| cmd_die!("thread $i failed, Error: $e"));
54+
.unwrap_or_else(|_| cmd_die!("thread $i failed"));
5555
cmd_info!("thread $i bandwidth: $bandwidth");
5656
});
5757
let total_bandwidth =

examples/dd_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ fn main() -> CmdResult {
5454
sudo bash -c "dd if=$file of=/dev/null bs=$block_size skip=$off count=$cnt 2>&1"
5555
| awk r#"/copied/{print $(NF-1) " " $NF}"#
5656
)
57-
.unwrap_or_else(|e| cmd_die!("thread $i failed, Error: $e"));
57+
.unwrap_or_else(|_| cmd_die!("thread $i failed"));
5858
cmd_info!("thread $i bandwidth: $bandwidth");
5959
});
6060
let total_bandwidth =

macros/src/lexer.rs

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::parser::{ParseArg, Parser};
22
use proc_macro2::{token_stream, Delimiter, Ident, Literal, Span, TokenStream, TokenTree};
33
use proc_macro_error::abort;
44
use quote::quote;
5+
use std::ffi::OsString;
56
use std::iter::Peekable;
67

78
// Scan string literal to tokenstream, used by most of the macros
@@ -13,18 +14,18 @@ use std::iter::Peekable;
1314
pub fn scan_str_lit(lit: &Literal) -> TokenStream {
1415
let s = lit.to_string();
1516
if !s.starts_with('\"') {
16-
return quote!(#lit);
17+
return quote!(::cmd_lib::CmdString::default().append(&#lit.to_owned()));
1718
}
1819
let mut iter = s[1..s.len() - 1] // To trim outside ""
1920
.chars()
2021
.peekable();
21-
let mut output = quote!("");
22-
let mut last_part = String::new();
23-
fn seal_last_part(last_part: &mut String, output: &mut TokenStream) {
22+
let mut output = quote!(::cmd_lib::CmdString::default());
23+
let mut last_part = OsString::new();
24+
fn seal_last_part(last_part: &mut OsString, output: &mut TokenStream) {
2425
if !last_part.is_empty() {
25-
let lit_str = format!("\"{}\"", last_part);
26+
let lit_str = format!("\"{}\"", last_part.to_str().unwrap());
2627
let l = syn::parse_str::<Literal>(&lit_str).unwrap();
27-
output.extend(quote!(+ #l));
28+
output.extend(quote!(.append(&#l)));
2829
last_part.clear();
2930
}
3031
}
@@ -33,7 +34,7 @@ pub fn scan_str_lit(lit: &Literal) -> TokenStream {
3334
if ch == '$' {
3435
if iter.peek() == Some(&'$') {
3536
iter.next();
36-
last_part.push('$');
37+
last_part.push("$");
3738
continue;
3839
}
3940

@@ -63,12 +64,12 @@ pub fn scan_str_lit(lit: &Literal) -> TokenStream {
6364
}
6465
if !var.is_empty() {
6566
let var = syn::parse_str::<Ident>(&var).unwrap();
66-
output.extend(quote!(+ &#var.to_string()));
67+
output.extend(quote!(.append(&#var.to_owned())));
6768
} else {
68-
output.extend(quote!(+ "$"));
69+
output.extend(quote!(.append(&"$")));
6970
}
7071
} else {
71-
last_part.push(ch);
72+
last_part.push(ch.to_string());
7273
}
7374
}
7475
seal_last_part(&mut last_part, &mut output);
@@ -123,7 +124,7 @@ impl Lexer {
123124
}
124125
TokenTree::Ident(ident) => {
125126
let s = ident.to_string();
126-
self.extend_last_arg(quote!(#s));
127+
self.extend_last_arg(quote!(&#s));
127128
}
128129
TokenTree::Punct(punct) => {
129130
let ch = punct.as_char();
@@ -142,7 +143,7 @@ impl Lexer {
142143
self.scan_dollar();
143144
} else {
144145
let s = ch.to_string();
145-
self.extend_last_arg(quote!(#s));
146+
self.extend_last_arg(quote!(&#s));
146147
}
147148
}
148149
}
@@ -200,9 +201,9 @@ impl Lexer {
200201

201202
fn extend_last_arg(&mut self, stream: TokenStream) {
202203
if self.last_arg_str.is_empty() {
203-
self.last_arg_str = quote!(String::new());
204+
self.last_arg_str = quote!(::cmd_lib::CmdString::default());
204205
}
205-
self.last_arg_str.extend(quote!(+ #stream));
206+
self.last_arg_str.extend(quote!(.append(#stream)));
206207
}
207208

208209
fn check_set_redirect(redirect: &mut bool, name: &str, span: Span) {
@@ -236,7 +237,8 @@ impl Lexer {
236237
let s = lit.to_string();
237238
if s.starts_with('\"') || s.starts_with('r') {
238239
// string literal
239-
self.extend_last_arg(scan_str_lit(&lit));
240+
let ss = scan_str_lit(&lit);
241+
self.extend_last_arg(quote!(&#ss));
240242
} else {
241243
let mut is_redirect = false;
242244
if s == "1" || s == "2" {
@@ -249,7 +251,7 @@ impl Lexer {
249251
}
250252
}
251253
if !is_redirect {
252-
self.extend_last_arg(quote!(#s));
254+
self.extend_last_arg(quote!(&#s));
253255
}
254256
}
255257
}
@@ -363,7 +365,7 @@ impl Lexer {
363365
let peek_no_gap = self.iter.peek_no_gap().map(|tt| tt.to_owned());
364366
// let peek_no_gap = None;
365367
if let Some(TokenTree::Ident(var)) = peek_no_gap {
366-
self.extend_last_arg(quote!(&#var.to_string()));
368+
self.extend_last_arg(quote!(&#var.to_owned()));
367369
} else if let Some(TokenTree::Group(g)) = peek_no_gap {
368370
if g.delimiter() != Delimiter::Brace && g.delimiter() != Delimiter::Bracket {
369371
abort!(
@@ -380,7 +382,7 @@ impl Lexer {
380382
abort!(span, "more than one variable in grouping");
381383
}
382384
if g.delimiter() == Delimiter::Brace {
383-
self.extend_last_arg(quote!(&#var.to_string()));
385+
self.extend_last_arg(quote!(&#var.to_owned()));
384386
} else {
385387
if !self.last_arg_str.is_empty() {
386388
abort!(span, "vector variable can only be used alone");

macros/src/lib.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -192,23 +192,23 @@ pub fn spawn(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
192192
#[proc_macro_error]
193193
pub fn cmd_error(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
194194
let msg = parse_msg(input.into());
195-
quote!(::cmd_lib::log::error!("{}", #msg)).into()
195+
quote!(::cmd_lib::log::error!("{:?}", #msg)).into()
196196
}
197197

198198
/// Logs a message at the warn level with interpolation support
199199
#[proc_macro]
200200
#[proc_macro_error]
201201
pub fn cmd_warn(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
202202
let msg = parse_msg(input.into());
203-
quote!(::cmd_lib::log::warn!("{}", #msg)).into()
203+
quote!(::cmd_lib::log::warn!("{:?}", #msg)).into()
204204
}
205205

206206
/// Print a message to stdout with interpolation support
207207
#[proc_macro]
208208
#[proc_macro_error]
209209
pub fn cmd_echo(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
210210
let msg = parse_msg(input.into());
211-
quote!(println!("{}", #msg)).into()
211+
quote!(println!("{:?}", #msg)).into()
212212
}
213213

214214
/// Logs a message at the info level with interpolation support
@@ -225,23 +225,23 @@ pub fn cmd_echo(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
225225
#[proc_macro_error]
226226
pub fn cmd_info(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
227227
let msg = parse_msg(input.into());
228-
quote!(::cmd_lib::log::info!("{}", #msg)).into()
228+
quote!(::cmd_lib::log::info!("{:?}", #msg)).into()
229229
}
230230

231231
/// Logs a message at the debug level with interpolation support
232232
#[proc_macro]
233233
#[proc_macro_error]
234234
pub fn cmd_debug(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
235235
let msg = parse_msg(input.into());
236-
quote!(::cmd_lib::log::debug!("{}", #msg)).into()
236+
quote!(::cmd_lib::log::debug!("{:?}", #msg)).into()
237237
}
238238

239239
/// Logs a message at the trace level with interpolation support
240240
#[proc_macro]
241241
#[proc_macro_error]
242242
pub fn cmd_trace(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
243243
let msg = parse_msg(input.into());
244-
quote!(::cmd_lib::log::trace!("{}", #msg)).into()
244+
quote!(::cmd_lib::log::trace!("{:?}", #msg)).into()
245245
}
246246

247247
#[proc_macro]
@@ -263,22 +263,22 @@ pub fn cmd_trace(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
263263
pub fn cmd_die(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
264264
let msg = parse_msg(input.into());
265265
quote!({
266-
::cmd_lib::log::error!("FATAL: {}", #msg);
266+
::cmd_lib::log::error!("FATAL: {:?}", #msg);
267267
std::process::exit(1)
268268
})
269269
.into()
270270
}
271271

272272
fn parse_msg(input: TokenStream) -> TokenStream {
273273
let mut iter = input.into_iter();
274-
let mut output = quote!(String::new());
274+
let mut output = TokenStream::new();
275275
let mut valid = false;
276276
if let Some(ref tt) = iter.next() {
277277
if let TokenTree::Literal(lit) = tt {
278278
let s = lit.to_string();
279279
if s.starts_with('\"') || s.starts_with('r') {
280280
let str_lit = lexer::scan_str_lit(&lit);
281-
output.extend(quote!(+ #str_lit));
281+
output.extend(quote!(#str_lit));
282282
valid = true;
283283
}
284284
}

macros/src/parser.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -88,23 +88,22 @@ impl<I: Iterator<Item = ParseArg>> Parser<I> {
8888
ParseRedirectFile(fd1, file, append) => {
8989
let mut redirect = quote!(::cmd_lib::Redirect);
9090
match fd1 {
91-
0 => redirect
92-
.extend(quote!(::FileToStdin(::std::path::PathBuf::from(#file)))),
93-
1 => redirect.extend(
94-
quote!(::StdoutToFile(::std::path::PathBuf::from(#file), #append)),
95-
),
96-
2 => redirect.extend(
97-
quote!(::StderrToFile(::std::path::PathBuf::from(#file), #append)),
98-
),
91+
0 => redirect.extend(quote!(::FileToStdin(#file.into_path_buf()))),
92+
1 => {
93+
redirect.extend(quote!(::StdoutToFile(#file.into_path_buf(), #append)))
94+
}
95+
2 => {
96+
redirect.extend(quote!(::StderrToFile(#file.into_path_buf(), #append)))
97+
}
9998
_ => panic!("unsupported fd ({}) redirect to file {}", fd1, file),
10099
}
101100
ret.extend(quote!(.add_redirect(#redirect)));
102101
}
103102
ParseArgStr(opt) => {
104-
ret.extend(quote!(.add_arg(#opt)));
103+
ret.extend(quote!(.add_arg(#opt.into_os_string())));
105104
}
106105
ParseArgVec(opts) => {
107-
ret.extend(quote! (.add_args(#opts.iter().map(|s| s.to_string()).collect::<Vec<String>>())));
106+
ret.extend(quote! (.add_args(#opts.iter().map(|s| ::std::ffi::OsString::from(s)).collect())));
108107
}
109108
ParsePipe | ParseOr | ParseSemicolon => break,
110109
}

src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
//! sudo bash -c "dd if=$file of=/dev/null bs=$block_size skip=$off count=$cnt 2>&1"
5858
//! | awk r#"/copied/{print $(NF-1) " " $NF}"#
5959
//! )
60-
//! .unwrap_or_else(|e| cmd_die!("thread $i failed, Error: $e"));
60+
//! .unwrap_or_else(|_| cmd_die!("thread $i failed"));
6161
//! cmd_info!("thread $i bandwidth: $bandwidth");
6262
//! });
6363
//! let total_bandwidth =
@@ -335,7 +335,9 @@ pub use child::CmdChildren;
335335
#[doc(hidden)]
336336
pub use log;
337337
pub use logger::init_builtin_logger;
338-
pub use process::{export_cmd, set_debug, set_pipefail, Cmd, CmdEnv, Cmds, GroupCmds, Redirect};
338+
pub use process::{
339+
export_cmd, set_debug, set_pipefail, Cmd, CmdEnv, CmdString, Cmds, GroupCmds, Redirect,
340+
};
339341

340342
mod builtins;
341343
mod child;

0 commit comments

Comments
 (0)