1212//! .unwrap();
1313//! ```
1414
15+ use std:: error:: Error ;
1516use std:: ffi;
17+ use std:: fmt;
1618use std:: path;
1719use std:: process;
1820
1921use escargot;
20- use failure;
2122
2223/// Create a `Command` for a `bin` in the Cargo project.
2324pub trait CommandCargoExt
3940 /// .unwrap()
4041 /// .unwrap();
4142 /// ```
42- fn main_binary ( ) -> Result < Self , failure :: Error > ;
43+ fn main_binary ( ) -> Result < Self , CargoError > ;
4344
4445 /// Create a `Command` to run a specific binary of the current crate.
4546 ///
5455 /// .unwrap()
5556 /// .unwrap();
5657 /// ```
57- fn cargo_bin < S : AsRef < ffi:: OsStr > > ( name : S ) -> Result < Self , failure :: Error > ;
58+ fn cargo_bin < S : AsRef < ffi:: OsStr > > ( name : S ) -> Result < Self , CargoError > ;
5859
5960 /// Create a `Command` to run a specific example of the current crate.
6061 ///
@@ -69,21 +70,21 @@ where
6970 /// .unwrap()
7071 /// .unwrap();
7172 /// ```
72- fn cargo_example < S : AsRef < ffi:: OsStr > > ( name : S ) -> Result < Self , failure :: Error > ;
73+ fn cargo_example < S : AsRef < ffi:: OsStr > > ( name : S ) -> Result < Self , CargoError > ;
7374}
7475
7576impl CommandCargoExt for process:: Command {
76- fn main_binary ( ) -> Result < Self , failure :: Error > {
77+ fn main_binary ( ) -> Result < Self , CargoError > {
7778 let cmd = main_binary_path ( ) ?;
7879 Ok ( process:: Command :: new ( & cmd) )
7980 }
8081
81- fn cargo_bin < S : AsRef < ffi:: OsStr > > ( name : S ) -> Result < Self , failure :: Error > {
82+ fn cargo_bin < S : AsRef < ffi:: OsStr > > ( name : S ) -> Result < Self , CargoError > {
8283 let cmd = cargo_bin_path ( name) ?;
8384 Ok ( process:: Command :: new ( & cmd) )
8485 }
8586
86- fn cargo_example < S : AsRef < ffi:: OsStr > > ( name : S ) -> Result < Self , failure :: Error > {
87+ fn cargo_example < S : AsRef < ffi:: OsStr > > ( name : S ) -> Result < Self , CargoError > {
8788 let cmd = cargo_example_path ( name) ?;
8889 Ok ( process:: Command :: new ( & cmd) )
8990 }
@@ -126,41 +127,103 @@ fn extract_filenames(msg: &escargot::Message, kind: &str) -> Option<path::PathBu
126127/// Get the path to the crate's main binary.
127128///
128129/// Note: only works if there one bin in the crate.
129- pub fn main_binary_path ( ) -> Result < path:: PathBuf , failure :: Error > {
130+ pub fn main_binary_path ( ) -> Result < path:: PathBuf , CargoError > {
130131 let cargo = escargot:: Cargo :: new ( ) . build ( ) . current_release ( ) ;
131132 let bins: Vec < _ > = cargo
132- . exec ( ) ?
133+ . exec ( )
134+ . map_err ( |e| CargoError :: with_cause ( e) ) ?
133135 . filter_map ( |m| extract_filenames ( & m, "bin" ) )
134136 . collect ( ) ;
135137 if bins. is_empty ( ) {
136- bail ! ( "No binaries in crate" ) ;
138+ return Err ( CargoError :: with_context ( "No binaries in crate" ) ) ;
137139 } else if bins. len ( ) != 1 {
138- bail ! ( "Ambiguous which binary is intended: {:?}" , bins) ;
140+ return Err ( CargoError :: with_context ( format ! (
141+ "Ambiguous which binary is intended: {:?}" ,
142+ bins
143+ ) ) ) ;
139144 }
140145 Ok ( bins. into_iter ( ) . next ( ) . expect ( "already validated" ) )
141146}
142147
143148/// Get the path to the specified binary of the current crate.
144- pub fn cargo_bin_path < S : AsRef < ffi:: OsStr > > ( name : S ) -> Result < path:: PathBuf , failure :: Error > {
149+ pub fn cargo_bin_path < S : AsRef < ffi:: OsStr > > ( name : S ) -> Result < path:: PathBuf , CargoError > {
145150 let cargo = escargot:: Cargo :: new ( ) . build ( ) . bin ( name) . current_release ( ) ;
146151 let bins: Vec < _ > = cargo
147- . exec ( ) ?
152+ . exec ( )
153+ . map_err ( |e| CargoError :: with_cause ( e) ) ?
148154 . filter_map ( |m| extract_filenames ( & m, "bin" ) )
149155 . collect ( ) ;
150156 assert_eq ! ( bins. len( ) , 1 ) ;
151157 Ok ( bins. into_iter ( ) . next ( ) . expect ( "already validated" ) )
152158}
153159
154160/// Get the path to the specified example of the current crate.
155- pub fn cargo_example_path < S : AsRef < ffi:: OsStr > > ( name : S ) -> Result < path:: PathBuf , failure :: Error > {
161+ pub fn cargo_example_path < S : AsRef < ffi:: OsStr > > ( name : S ) -> Result < path:: PathBuf , CargoError > {
156162 let cargo = escargot:: Cargo :: new ( )
157163 . build ( )
158164 . example ( name)
159165 . current_release ( ) ;
160166 let bins: Vec < _ > = cargo
161- . exec ( ) ?
167+ . exec ( )
168+ . map_err ( |e| CargoError :: with_cause ( e) ) ?
162169 . filter_map ( |m| extract_filenames ( & m, "example" ) )
163170 . collect ( ) ;
164171 assert_eq ! ( bins. len( ) , 1 ) ;
165172 Ok ( bins. into_iter ( ) . next ( ) . expect ( "already validated" ) )
166173}
174+
175+ /// Error when finding crate binary.
176+ #[ derive( Debug ) ]
177+ pub struct CargoError {
178+ context : Option < String > ,
179+ cause : Option < Box < Error + Send + Sync + ' static > > ,
180+ }
181+
182+ impl CargoError {
183+ fn with_context < S > ( context : S ) -> Self
184+ where
185+ S : Into < String > ,
186+ {
187+ let context = context. into ( ) ;
188+ Self {
189+ context : Some ( context) ,
190+ cause : None ,
191+ }
192+ }
193+
194+ fn with_cause < E > ( cause : E ) -> Self
195+ where
196+ E : Error + Send + Sync + ' static ,
197+ {
198+ let cause = Box :: new ( cause) ;
199+ Self {
200+ context : None ,
201+ cause : Some ( cause) ,
202+ }
203+ }
204+ }
205+
206+ impl Error for CargoError {
207+ fn description ( & self ) -> & str {
208+ "Cargo command failed."
209+ }
210+
211+ fn cause ( & self ) -> Option < & Error > {
212+ self . cause . as_ref ( ) . map ( |c| {
213+ let c: & Error = c. as_ref ( ) ;
214+ c
215+ } )
216+ }
217+ }
218+
219+ impl fmt:: Display for CargoError {
220+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
221+ if let Some ( ref context) = self . context {
222+ writeln ! ( f, "{}" , context) ?;
223+ }
224+ if let Some ( ref cause) = self . cause {
225+ writeln ! ( f, "Cause: {}" , cause) ?;
226+ }
227+ Ok ( ( ) )
228+ }
229+ }
0 commit comments