xaizek / rocketgit (License: AGPLv3+) (since 2018-12-09)
Light and fast Git hosting solution suitable to serve both as a hub or as a personal code storage with its tickets, pull requests, API and much more.
Commit b550d45c19c48235eddbd5b6fdcadcec2689065b

rg_exec: when stdout closes, we should not try to get input anymore from the external program
Author: Catalin(ux) M. BOIE
Author date (UTC): 2017-07-09 06:38
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2017-07-09 06:38
Parent(s): 68c2120f6bb1cd04e3c35b18fee8c2ce89c525bb
Signing key:
Tree: 8ad1ef6f371fc733509d7ce7f602387364be5455
File Lines added Lines deleted
inc/util.inc.php 27 24
File inc/util.inc.php changed (mode: 100644) (index 44ecd5c..79ed7cd)
... ... function rg_exec($cmd, $input, $cb_stdout, $cb_stderr)
1026 1026 rg_prof_start('exec'); rg_prof_start('exec');
1027 1027 rg_log_enter('Executing [' . $cmd . ']'); rg_log_enter('Executing [' . $cmd . ']');
1028 1028
1029 // DEBUG
1030 $d = FALSE;
1031
1029 1032 $ret = array(); $ret = array();
1030 1033 $ret['ok'] = 0; $ret['ok'] = 0;
1031 1034 $ret['errmsg'] = ''; $ret['errmsg'] = '';
 
... ... function rg_exec($cmd, $input, $cb_stdout, $cb_stderr)
1038 1041 1 => array('pipe', 'w'), 1 => array('pipe', 'w'),
1039 1042 2 => array("pipe", "w") 2 => array("pipe", "w")
1040 1043 ); );
1041 //rg_log_ml('DEBUG: desc: ' . print_r($desc, TRUE));
1044 $d && rg_log_ml('DEBUG: desc: ' . print_r($desc, TRUE));
1042 1045
1043 1046 $a = proc_open($cmd, $desc, $pipes); $a = proc_open($cmd, $desc, $pipes);
1044 1047 if ($a === FALSE) { if ($a === FALSE) {
 
... ... function rg_exec($cmd, $input, $cb_stdout, $cb_stderr)
1046 1049 break; break;
1047 1050 } }
1048 1051
1049 //rg_log_ml('DEBUG: proc_open pipes: ' . print_r($pipes, TRUE));
1052 $d && rg_log_ml('DEBUG: proc_open pipes: ' . print_r($pipes, TRUE));
1050 1053
1051 1054 $rx = array($pipes[1], $pipes[2]); $rx = array($pipes[1], $pipes[2]);
1052 1055 $wx = array(); $wx = array();
 
... ... function rg_exec($cmd, $input, $cb_stdout, $cb_stderr)
1056 1059 $revents = $rx; $revents = $rx;
1057 1060 $wevents = $wx; $wevents = $wx;
1058 1061 $ex = NULL; $ex = NULL;
1062 $d && rg_log('DEBUG: before stream_select:'
1063 . ' revents: ' . rg_array2string($revents)
1064 . ' wevents: ' . rg_array2string($wevents));
1059 1065 $r = stream_select($revents, $wevents, $ex, 5, 0); $r = stream_select($revents, $wevents, $ex, 5, 0);
1060 1066 if ($r === FALSE) { if ($r === FALSE) {
1061 1067 $ret['errmsg'] = "cannot select"; $ret['errmsg'] = "cannot select";
 
... ... function rg_exec($cmd, $input, $cb_stdout, $cb_stderr)
1067 1073 rg_log_ml('ps: ' . print_r($ps, TRUE)); rg_log_ml('ps: ' . print_r($ps, TRUE));
1068 1074 //rg_log('DEBUG: No activity (conn status=' . connection_status() . ')!'); //rg_log('DEBUG: No activity (conn status=' . connection_status() . ')!');
1069 1075 if (connection_aborted()) { if (connection_aborted()) {
1076 $d && rg_log('connection aborted');
1070 1077 $ret['errmsg'] = 'connection aborted'; $ret['errmsg'] = 'connection aborted';
1071 1078 break; break;
1072 1079 } }
1073 1080 continue; continue;
1074 1081 } }
1075 1082
1076 //rg_log('DEBUG: stream_select returned ' . $r
1077 // . ' revents: ' . rg_array2string($revents)
1078 // . ' wevents: ' . rg_array2string($wevents)
1079 // . ' ex: ' . rg_array2string($ex));
1083 $d && rg_log('DEBUG: stream_select returned ' . $r
1084 . ' revents: ' . rg_array2string($revents)
1085 . ' wevents: ' . rg_array2string($wevents)
1086 . ' ex: ' . rg_array2string($ex));
1080 1087
1081 1088 foreach ($wevents as $fd) { foreach ($wevents as $fd) {
1082 1089 if (!empty($ret['errmsg'])) if (!empty($ret['errmsg']))
1083 1090 break; break;
1084 1091
1085 //rg_log('DEBUG: write event on fd ' . $fd . '!');
1092 $d && rg_log('DEBUG: write event on fd ' . $fd . '!');
1086 1093
1087 //rg_log('DEBUG: Writing to fd ' . $fd
1088 // . ' [' . $input . ']...');
1094 $d && rg_log('DEBUG: Writing to fd ' . $fd
1095 . ' [' . $input . ']...');
1089 1096 $r = @fwrite($fd, $input); $r = @fwrite($fd, $input);
1090 1097 if ($r === FALSE) { if ($r === FALSE) {
1091 1098 $ret['ermsg'] = 'cannot write'; $ret['ermsg'] = 'cannot write';
1092 1099 break; break;
1093 1100 } }
1094 //rg_log('DEBUG: fwrite returned ' . $r . '.');
1101 $d && rg_log('DEBUG: fwrite returned ' . $r . '.');
1095 1102 $input = substr($input, $r); $input = substr($input, $r);
1096 1103 if (empty($input)) if (empty($input))
1097 1104 $wx = array(); $wx = array();
1098 1105 } }
1099 1106
1107 $do_break = FALSE;
1100 1108 foreach ($revents as $fd) { foreach ($revents as $fd) {
1101 1109 if (!empty($ret['errmsg'])) if (!empty($ret['errmsg']))
1102 1110 break; break;
1103 1111
1104 //rg_log('DEBUG: read event on fd ' . $fd . '!');
1112 $d && rg_log('DEBUG: read event on fd ' . $fd . '!');
1105 1113 $_d = fread($fd, 32 * 4096); $_d = fread($fd, 32 * 4096);
1106 1114 if ($_d === FALSE) { if ($_d === FALSE) {
1107 1115 $ret['errmsg'] = "cannot read"; $ret['errmsg'] = "cannot read";
 
... ... function rg_exec($cmd, $input, $cb_stdout, $cb_stderr)
1109 1117 } }
1110 1118
1111 1119 if (empty($_d)) { if (empty($_d)) {
1112 //rg_log('DEBUG: stream ' . $fd . ' returned no data.');
1113 foreach ($rx as $_k => $_fd) {
1114 if ($_fd === $fd) {
1115 unset($rx[$_k]);
1116 break;
1117 }
1118 }
1119 continue;
1120 $d && rg_log('DEBUG: stream ' . $fd . ' returned no data.');
1121 $do_break = TRUE;
1122 break;
1120 1123 } }
1121 1124
1122 1125 if ($fd === $pipes[2]) { if ($fd === $pipes[2]) {
1123 1126 if ($cb_stderr === FALSE) { if ($cb_stderr === FALSE) {
1124 //rg_log('DEBUG: fd is pipes[2], append to stderr var: ' . $_d);
1127 $d && rg_log('DEBUG: fd is pipes[2], append to stderr var: ' . $_d);
1125 1128 $ret['stderr'] .= $_d; $ret['stderr'] .= $_d;
1126 1129 } else { } else {
1127 //rg_log('DEBUG: fd is pipes[2], call stdout cb:' . $_d);
1130 $d && rg_log('DEBUG: fd is pipes[2], call stdout cb:' . $_d);
1128 1131 $cb_stderr($_d); $cb_stderr($_d);
1129 1132 // We want the last error message to be able to log something // We want the last error message to be able to log something
1130 1133 $ret['stderr'] = $_d; $ret['stderr'] = $_d;
1131 1134 } }
1132 1135 } else if ($fd === $pipes[1]) { } else if ($fd === $pipes[1]) {
1133 1136 if ($cb_stdout === FALSE) { if ($cb_stdout === FALSE) {
1134 //rg_log('DEBUG: fd is pipes[1], append to stdout var: ' . $_d);
1137 $d && rg_log('DEBUG: fd is pipes[1], append to stdout var: ' . $_d);
1135 1138 $ret['data'] .= $_d; $ret['data'] .= $_d;
1136 1139 } else { } else {
1137 //rg_log('DEBUG: fd is pipes[1], call stdout cb: ' . $_d);
1140 $d && rg_log('DEBUG: fd is pipes[1], call stdout cb: ' . $_d);
1138 1141 $cb_stdout($_d); $cb_stdout($_d);
1139 1142 } }
1140 1143 } else { } else {
 
... ... function rg_exec($cmd, $input, $cb_stdout, $cb_stderr)
1142 1145 } }
1143 1146 } }
1144 1147
1145 if (!empty($ret['errmsg']))
1148 if ($do_break || !empty($ret['errmsg']))
1146 1149 break; break;
1147 1150 } }
1148 1151 $ret['stderr'] = trim($ret['stderr']); $ret['stderr'] = trim($ret['stderr']);
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/rocketgit

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/rocketgit

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master