1#include "Perforce.h" 2#include "log.h" 3#include <string.h> 4#include <cstdio> 5#include <stdlib.h> 6#include <sstream> 7#include <sys/types.h> 8#include <unistd.h> 9#include <stdlib.h> 10#include <string.h> 11#include <sys/wait.h> 12#include <cstdio> 13 14using namespace std; 15 16extern char** environ; 17 18int 19Perforce::RunCommand(const string& cmd, string* result, bool printOnFailure) 20{ 21 int err; 22 int outPipe[2]; 23 int errPipe[2]; 24 pid_t pid; 25 26 log_printf("Perforce::RunCommand: %s\n", cmd.c_str()); 27 28 err = pipe(outPipe); 29 err |= pipe(errPipe); 30 if (err == -1) { 31 printf("couldn't create pipe. exiting.\n"); 32 exit(1); 33 return -1; 34 } 35 36 pid = fork(); 37 if (pid == -1) { 38 printf("couldn't fork. eixiting\n"); 39 exit(1); 40 return -1; 41 } 42 else if (pid == 0) { 43 char const* args[] = { 44 "/bin/sh", 45 "-c", 46 cmd.c_str(), 47 NULL 48 }; 49 close(outPipe[0]); 50 close(errPipe[0]); 51 dup2(outPipe[1], 1); 52 dup2(errPipe[1], 2); 53 execve(args[0], (char* const*)args, environ); 54 // done 55 } 56 57 close(outPipe[1]); 58 close(errPipe[1]); 59 60 result->clear(); 61 62 char buf[1024]; 63 64 // stdout 65 while (true) { 66 size_t amt = read(outPipe[0], buf, sizeof(buf)); 67 result->append(buf, amt); 68 if (amt <= 0) { 69 break; 70 } 71 } 72 73 // stderr -- the messages are short so it ought to just fit in the buffer 74 string error; 75 while (true) { 76 size_t amt = read(errPipe[0], buf, sizeof(buf)); 77 error.append(buf, amt); 78 if (amt <= 0) { 79 break; 80 } 81 } 82 83 close(outPipe[0]); 84 close(errPipe[0]); 85 86 waitpid(pid, &err, 0); 87 if (WIFEXITED(err)) { 88 err = WEXITSTATUS(err); 89 } else { 90 err = -1; 91 } 92 if (err != 0 && printOnFailure) { 93 write(2, error.c_str(), error.length()); 94 } 95 return err; 96} 97 98int 99Perforce::GetResourceFileNames(const string& version, const string& base, 100 const vector<string>& apps, vector<string>* results, 101 bool printOnFailure) 102{ 103 int err; 104 string text; 105 stringstream cmd; 106 107 cmd << "p4 files"; 108 109 const size_t I = apps.size(); 110 for (size_t i=0; i<I; i++) { 111 cmd << " \"" << base << '/' << apps[i] << "/res/values/strings.xml@" << version << '"'; 112 } 113 114 err = RunCommand(cmd.str(), &text, printOnFailure); 115 116 const char* str = text.c_str(); 117 while (*str) { 118 const char* lineend = strchr(str, '\n'); 119 if (lineend == str) { 120 str++; 121 continue; 122 } 123 if (lineend-str > 1023) { 124 fprintf(stderr, "line too long!\n"); 125 return 1; 126 } 127 128 string s(str, lineend-str); 129 130 char filename[1024]; 131 char edit[1024]; 132 int count = sscanf(str, "%[^#]#%*d - %s change %*d %*[^\n]\n", filename, edit); 133 134 if (count == 2 && 0 != strcmp("delete", edit)) { 135 results->push_back(string(filename)); 136 } 137 138 str = lineend + 1; 139 } 140 141 return err; 142} 143 144int 145Perforce::GetFile(const string& file, const string& version, string* result, 146 bool printOnFailure) 147{ 148 stringstream cmd; 149 cmd << "p4 print -q \"" << file << '@' << version << '"'; 150 return RunCommand(cmd.str(), result, printOnFailure); 151} 152 153string 154Perforce::GetCurrentChange(bool printOnFailure) 155{ 156 int err; 157 string text; 158 159 err = RunCommand("p4 changes -m 1 \\#have", &text, printOnFailure); 160 if (err != 0) { 161 return ""; 162 } 163 164 long long n; 165 int count = sscanf(text.c_str(), "Change %lld on", &n); 166 if (count != 1) { 167 return ""; 168 } 169 170 char result[100]; 171 sprintf(result, "%lld", n); 172 173 return string(result); 174} 175 176static int 177do_files(const string& op, const vector<string>& files, bool printOnFailure) 178{ 179 string text; 180 stringstream cmd; 181 182 cmd << "p4 " << op; 183 184 const size_t I = files.size(); 185 for (size_t i=0; i<I; i++) { 186 cmd << " \"" << files[i] << "\""; 187 } 188 189 return Perforce::RunCommand(cmd.str(), &text, printOnFailure); 190} 191 192int 193Perforce::EditFiles(const vector<string>& files, bool printOnFailure) 194{ 195 return do_files("edit", files, printOnFailure); 196} 197 198int 199Perforce::AddFiles(const vector<string>& files, bool printOnFailure) 200{ 201 return do_files("add", files, printOnFailure); 202} 203 204int 205Perforce::DeleteFiles(const vector<string>& files, bool printOnFailure) 206{ 207 return do_files("delete", files, printOnFailure); 208} 209 210string 211Perforce::Where(const string& depotPath, bool printOnFailure) 212{ 213 int err; 214 string text; 215 string cmd = "p4 where "; 216 cmd += depotPath; 217 218 err = RunCommand(cmd, &text, printOnFailure); 219 if (err != 0) { 220 return ""; 221 } 222 223 size_t index = text.find(' '); 224 if (index == text.npos) { 225 return ""; 226 } 227 index = text.find(' ', index+1)+1; 228 if (index == text.npos) { 229 return ""; 230 } 231 232 return text.substr(index, text.length()-index-1); 233} 234 235