@@ -67,12 +67,23 @@ use std::env;
67
67
use std:: error;
68
68
use std:: ffi:: { OsStr , OsString } ;
69
69
use std:: fmt;
70
+ use std:: fmt:: Display ;
70
71
use std:: io;
71
72
use std:: ops:: { Bound , RangeBounds } ;
72
73
use std:: path:: PathBuf ;
73
74
use std:: process:: { Command , Output } ;
74
75
use std:: str;
75
76
77
+ /// Wrapper struct to polyfill methods introduced in 1.57 (`get_envs`, `get_args` etc).
78
+ /// This is needed to reconstruct the pkg-config command for output in a copy-
79
+ /// paste friendly format via `Display`.
80
+ struct WrappedCommand {
81
+ inner : Command ,
82
+ program : OsString ,
83
+ env_vars : Vec < ( OsString , OsString ) > ,
84
+ args : Vec < OsString > ,
85
+ }
86
+
76
87
#[ derive( Clone , Debug ) ]
77
88
pub struct Config {
78
89
statik : Option < bool > ,
@@ -148,6 +159,81 @@ pub enum Error {
148
159
__Nonexhaustive,
149
160
}
150
161
162
+ impl WrappedCommand {
163
+ fn new < S : AsRef < OsStr > > ( program : S ) -> Self {
164
+ Self {
165
+ inner : Command :: new ( program. as_ref ( ) ) ,
166
+ program : program. as_ref ( ) . to_os_string ( ) ,
167
+ env_vars : Vec :: new ( ) ,
168
+ args : Vec :: new ( ) ,
169
+ }
170
+ }
171
+
172
+ fn args < I , S > ( & mut self , args : I ) -> & mut Self
173
+ where
174
+ I : IntoIterator < Item = S > + Clone ,
175
+ S : AsRef < OsStr > ,
176
+ {
177
+ self . inner . args ( args. clone ( ) ) ;
178
+ self . args
179
+ . extend ( args. into_iter ( ) . map ( |arg| arg. as_ref ( ) . to_os_string ( ) ) ) ;
180
+
181
+ self
182
+ }
183
+
184
+ fn arg < S : AsRef < OsStr > > ( & mut self , arg : S ) -> & mut Self {
185
+ self . inner . arg ( arg. as_ref ( ) ) ;
186
+ self . args . push ( arg. as_ref ( ) . to_os_string ( ) ) ;
187
+
188
+ self
189
+ }
190
+
191
+ fn env < K , V > ( & mut self , key : K , value : V ) -> & mut Self
192
+ where
193
+ K : AsRef < OsStr > ,
194
+ V : AsRef < OsStr > ,
195
+ {
196
+ self . inner . env ( key. as_ref ( ) , value. as_ref ( ) ) ;
197
+ self . env_vars
198
+ . push ( ( key. as_ref ( ) . to_os_string ( ) , value. as_ref ( ) . to_os_string ( ) ) ) ;
199
+
200
+ self
201
+ }
202
+
203
+ fn output ( & mut self ) -> io:: Result < Output > {
204
+ self . inner . output ( )
205
+ }
206
+ }
207
+
208
+ /// Output a command invocation that can be copy-pasted into the terminal.
209
+ /// `Command`'s existing debug implementation is not used for that reason,
210
+ /// as it can sometimes lead to output such as:
211
+ /// `PKG_CONFIG_ALLOW_SYSTEM_CFLAGS="1" PKG_CONFIG_ALLOW_SYSTEM_LIBS="1" "pkg-config" "--libs" "--cflags" "mylibrary"`
212
+ /// Which cannot be copy-pasted into terminals such as nushell, and is a bit noisy.
213
+ /// This will look something like:
214
+ /// `PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1 PKG_CONFIG_ALLOW_SYSTEM_LIBS=1 pkg-config --libs --cflags mylibrary`
215
+ impl Display for WrappedCommand {
216
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
217
+ // Format all explicitly defined environment variables
218
+ let envs = self
219
+ . env_vars
220
+ . iter ( )
221
+ . map ( |( env, arg) | format ! ( "{}={}" , env. to_string_lossy( ) , arg. to_string_lossy( ) ) )
222
+ . collect :: < Vec < String > > ( )
223
+ . join ( " " ) ;
224
+
225
+ // Format all pkg-config arguments
226
+ let args = self
227
+ . args
228
+ . iter ( )
229
+ . map ( |arg| arg. to_string_lossy ( ) . to_string ( ) )
230
+ . collect :: < Vec < String > > ( )
231
+ . join ( " " ) ;
232
+
233
+ write ! ( f, "{} {} {}" , envs, self . program. to_string_lossy( ) , args)
234
+ }
235
+ }
236
+
151
237
impl error:: Error for Error { }
152
238
153
239
impl fmt:: Debug for Error {
@@ -558,47 +644,21 @@ impl Config {
558
644
if output. status . success ( ) {
559
645
Ok ( output. stdout )
560
646
} else {
561
- // Collect all explicitly-defined environment variables
562
- // this is used to display the equivalent pkg-config shell invocation
563
- let envs = cmd
564
- . get_envs ( )
565
- . map ( |( env, optional_arg) | {
566
- if let Some ( arg) = optional_arg {
567
- format ! ( "{}={}" , env. to_string_lossy( ) , arg. to_string_lossy( ) )
568
- } else {
569
- env. to_string_lossy ( ) . to_string ( )
570
- }
571
- } )
572
- . collect :: < Vec < String > > ( ) ;
573
-
574
- // Collect arguments for the same reason
575
- let args = cmd
576
- . get_args ( )
577
- . map ( |arg| arg. to_string_lossy ( ) . to_string ( ) )
578
- . collect :: < Vec < String > > ( ) ;
579
-
580
- // This will look something like:
581
- // PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1 PKG_CONFIG_ALLOW_SYSTEM_LIBS=1 pkg-config --libs --cflags {library}
582
647
Err ( Error :: Failure {
583
- command : format ! (
584
- "{} {} {}" ,
585
- envs. join( " " ) ,
586
- cmd. get_program( ) . to_string_lossy( ) ,
587
- args. join( " " )
588
- ) ,
648
+ command : format ! ( "{}" , cmd) ,
589
649
output,
590
650
} )
591
651
}
592
652
}
593
653
Err ( cause) => Err ( Error :: Command {
594
- command : format ! ( "{:? }" , cmd) ,
654
+ command : format ! ( "{}" , cmd) ,
595
655
cause,
596
656
} ) ,
597
657
}
598
658
}
599
659
600
- fn command ( & self , exe : OsString , name : & str , args : & [ & str ] ) -> Command {
601
- let mut cmd = Command :: new ( exe) ;
660
+ fn command ( & self , exe : OsString , name : & str , args : & [ & str ] ) -> WrappedCommand {
661
+ let mut cmd = WrappedCommand :: new ( exe) ;
602
662
if self . is_static ( name) {
603
663
cmd. arg ( "--static" ) ;
604
664
}
0 commit comments