#include "Perforce.h" #include "log.h" #include <string.h> #include <cstdio> #include <stdlib.h> #include <sstream> #include <sys/types.h> #include <unistd.h> #include <sys/wait.h> using namespace std; extern char** environ; int Perforce::RunCommand(const string& cmd, string* result, bool printOnFailure) { int err; int outPipe[2]; int errPipe[2]; pid_t pid; log_printf("Perforce::RunCommand: %s\n", cmd.c_str()); err = pipe(outPipe); err |= pipe(errPipe); if (err == -1) { printf("couldn't create pipe. exiting.\n"); exit(1); return -1; } pid = fork(); if (pid == -1) { printf("couldn't fork. eixiting\n"); exit(1); return -1; } else if (pid == 0) { char const* args[] = { "/bin/sh", "-c", cmd.c_str(), NULL }; close(outPipe[0]); close(errPipe[0]); dup2(outPipe[1], 1); dup2(errPipe[1], 2); execve(args[0], (char* const*)args, environ); // done } close(outPipe[1]); close(errPipe[1]); result->clear(); char buf[1024]; // stdout while (true) { size_t amt = read(outPipe[0], buf, sizeof(buf)); result->append(buf, amt); if (amt <= 0) { break; } } // stderr -- the messages are short so it ought to just fit in the buffer string error; while (true) { size_t amt = read(errPipe[0], buf, sizeof(buf)); error.append(buf, amt); if (amt <= 0) { break; } } close(outPipe[0]); close(errPipe[0]); waitpid(pid, &err, 0); if (WIFEXITED(err)) { err = WEXITSTATUS(err); } else { err = -1; } if (err != 0 && printOnFailure) { write(2, error.c_str(), error.length()); } return err; } int Perforce::GetResourceFileNames(const string& version, const string& base, const vector<string>& apps, vector<string>* results, bool printOnFailure) { int err; string text; stringstream cmd; cmd << "p4 files"; const size_t I = apps.size(); for (size_t i=0; i<I; i++) { cmd << " \"" << base << '/' << apps[i] << "/res/values/strings.xml@" << version << '"'; } err = RunCommand(cmd.str(), &text, printOnFailure); const char* str = text.c_str(); while (*str) { const char* lineend = strchr(str, '\n'); if (lineend == str) { str++; continue; } if (lineend-str > 1023) { fprintf(stderr, "line too long!\n"); return 1; } string s(str, lineend-str); char filename[1024]; char edit[1024]; int count = sscanf(str, "%[^#]#%*d - %s change %*d %*[^\n]\n", filename, edit); if (count == 2 && 0 != strcmp("delete", edit)) { results->push_back(string(filename)); } str = lineend + 1; } return err; } int Perforce::GetFile(const string& file, const string& version, string* result, bool printOnFailure) { stringstream cmd; cmd << "p4 print -q \"" << file << '@' << version << '"'; return RunCommand(cmd.str(), result, printOnFailure); } string Perforce::GetCurrentChange(bool printOnFailure) { int err; string text; err = RunCommand("p4 changes -m 1 \\#have", &text, printOnFailure); if (err != 0) { return ""; } long long n; int count = sscanf(text.c_str(), "Change %lld on", &n); if (count != 1) { return ""; } char result[100]; sprintf(result, "%lld", n); return string(result); } static int do_files(const string& op, const vector<string>& files, bool printOnFailure) { string text; stringstream cmd; cmd << "p4 " << op; const size_t I = files.size(); for (size_t i=0; i<I; i++) { cmd << " \"" << files[i] << "\""; } return Perforce::RunCommand(cmd.str(), &text, printOnFailure); } int Perforce::EditFiles(const vector<string>& files, bool printOnFailure) { return do_files("edit", files, printOnFailure); } int Perforce::AddFiles(const vector<string>& files, bool printOnFailure) { return do_files("add", files, printOnFailure); } int Perforce::DeleteFiles(const vector<string>& files, bool printOnFailure) { return do_files("delete", files, printOnFailure); } string Perforce::Where(const string& depotPath, bool printOnFailure) { int err; string text; string cmd = "p4 where "; cmd += depotPath; err = RunCommand(cmd, &text, printOnFailure); if (err != 0) { return ""; } size_t index = text.find(' '); if (index == text.npos) { return ""; } index = text.find(' ', index+1)+1; if (index == text.npos) { return ""; } return text.substr(index, text.length()-index-1); }