@@ -2,18 +2,22 @@ use either::Either;
2
2
use libc;
3
3
use glob:: { self , MatchOptions } ;
4
4
use glob:: Pattern as GlobPattern ;
5
+ use nix:: unistd;
5
6
6
7
use std:: borrow:: Cow ;
7
8
use std:: cell:: RefCell ;
8
9
use std:: ffi:: { OsString , OsStr } ;
10
+ use std:: fmt;
9
11
use std:: fs:: { File , OpenOptions } ;
10
- use std:: io:: Write ;
12
+ use std:: io:: { Read , Write } ;
11
13
use std:: iter:: FromIterator ;
12
- use std:: os:: unix:: ffi:: OsStrExt ;
14
+ use std:: os:: unix:: ffi:: { OsStringExt , OsStrExt } ;
13
15
use std:: os:: unix:: io:: RawFd ;
14
16
use std:: process;
15
17
use std:: rc:: Rc ;
18
+ use std:: result:: Result as StdResult ;
16
19
20
+ use util:: RawFdWrapper ;
17
21
use super :: { NAME , UtilSetup } ;
18
22
use super :: command:: { CommandEnv , CommandWrapper , ExecData , ExecEnv , InProcessCommand } ;
19
23
use super :: env:: { EnvFd , Environment } ;
@@ -1034,12 +1038,61 @@ impl CommandSubst {
1034
1038
where
1035
1039
S : UtilSetup ,
1036
1040
{
1037
- // TODO: needs to enter a subshell, so i guess enter_scope()? if so, variables need
1038
- // Locality as well. maybe clone environment?
1039
- // TODO: this needs to use the same spawning mechanism used by piping, so a correct
1040
- // implementation depends on correct piping
1041
- let _ = self . command . execute ( setup, env) ; // just do this for now to make sure stuff works
1042
- unimplemented ! ( )
1041
+ // set stdout for the command to an anonymous pipe so we can retrieve the output and return
1042
+ // it later (NOTE: we might want to just do this in general if an output EnvFd is
1043
+ // EnvFd::Piped, in which case we would just set this EnvFd to EnvFd::Piped instead of
1044
+ // manually creating a pipe here)
1045
+ let ( read, write) = match self . write_error ( setup, env, unistd:: pipe ( ) ) {
1046
+ Ok ( m) => m,
1047
+ Err ( f) => return f,
1048
+ } ;
1049
+
1050
+ // TODO: enter_scope() needs to protect variables somehow, so I guess they need Locality as
1051
+ // well? Maybe clone env?
1052
+ env. enter_scope ( ) ;
1053
+
1054
+ env. set_local_fd ( 1 , EnvFd :: Fd ( RawFdWrapper :: new ( write, false , true ) ) ) ;
1055
+ let code = self . command . execute ( setup, env) ;
1056
+
1057
+ env. exit_scope ( ) ;
1058
+ env. special_vars ( ) . set_last_exitcode ( code) ;
1059
+
1060
+ // XXX: not sure if we want to just ignore
1061
+ unistd:: close ( write) ;
1062
+
1063
+ // read the output from the pipe into a vector
1064
+ let mut output = vec ! [ ] ;
1065
+ let res = self . write_error ( setup, env, RawFdWrapper :: new ( read, true , false ) . read_to_end ( & mut output) ) ;
1066
+
1067
+ // XXX: not sure if we want to just ignore these so let them create warnings for now
1068
+ unistd:: close ( read) ;
1069
+
1070
+ if let Err ( f) = res {
1071
+ return f;
1072
+ }
1073
+
1074
+ let size = {
1075
+ let mut iter = output. rsplitn ( 2 , |& byte| byte != b'\n' ) ;
1076
+ let last = iter. next ( ) . unwrap ( ) ;
1077
+ if iter. next ( ) . is_some ( ) {
1078
+ output. len ( ) - last. len ( )
1079
+ } else {
1080
+ output. len ( )
1081
+ }
1082
+ } ;
1083
+ output. truncate ( size) ;
1084
+ OsString :: from_vec ( output)
1085
+ }
1086
+
1087
+ fn write_error < S , T , U > ( & self , setup : & mut S , env : & mut Environment , res : StdResult < T , U > ) -> StdResult < T , OsString >
1088
+ where
1089
+ S : UtilSetup ,
1090
+ U : fmt:: Display ,
1091
+ {
1092
+ write_error ( setup, res) . map_err ( |code| {
1093
+ env. special_vars ( ) . set_last_exitcode ( code) ;
1094
+ OsString :: new ( )
1095
+ } )
1043
1096
}
1044
1097
}
1045
1098
@@ -1259,3 +1312,20 @@ where
1259
1312
}
1260
1313
code
1261
1314
}
1315
+
1316
+ fn write_error < S , T , U > ( setup : & mut S , result : StdResult < T , U > ) -> StdResult < T , ExitCode >
1317
+ where
1318
+ S : UtilSetup ,
1319
+ U : fmt:: Display ,
1320
+ {
1321
+ match result {
1322
+ Ok ( m) => Ok ( m) ,
1323
+ Err ( f) => {
1324
+ // FIXME: needs to print out line number
1325
+ // XXX: should we ignore any I/O errors?
1326
+ let _ = display_msg ! ( setup. error( ) , "{}" , f) ;
1327
+ // FIXME: this could be different depending on the type of error
1328
+ Err ( 127 )
1329
+ }
1330
+ }
1331
+ }
0 commit comments