| The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 1 | #include "Perforce.h" | 
 | 2 | #include "log.h" | 
| The Android Open Source Project | b798689 | 2009-01-09 17:51:23 -0800 | [diff] [blame] | 3 | #include <string.h> | 
| Jack Palevich | bdb087c | 2009-06-24 19:01:27 -0700 | [diff] [blame] | 4 | #include <cstdio> | 
| The Android Open Source Project | b798689 | 2009-01-09 17:51:23 -0800 | [diff] [blame] | 5 | #include <stdlib.h> | 
| The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 6 | #include <sstream> | 
 | 7 | #include <sys/types.h> | 
 | 8 | #include <unistd.h> | 
| Alexey Zaytsev | 862bfdb | 2008-10-22 02:05:55 +0400 | [diff] [blame] | 9 | #include <stdlib.h> | 
 | 10 | #include <string.h> | 
| The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 11 | #include <sys/wait.h> | 
| Scott Tsai | 8a2b908 | 2009-03-21 08:08:36 +0800 | [diff] [blame] | 12 | #include <cstdio> | 
| The Android Open Source Project | 54b6cfa | 2008-10-21 07:00:00 -0700 | [diff] [blame] | 13 |  | 
 | 14 | using namespace std; | 
 | 15 |  | 
 | 16 | extern char** environ; | 
 | 17 |  | 
 | 18 | int | 
 | 19 | Perforce::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 |  | 
 | 98 | int | 
 | 99 | Perforce::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 |  | 
 | 144 | int | 
 | 145 | Perforce::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 |  | 
 | 153 | string | 
 | 154 | Perforce::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 |  | 
 | 176 | static int | 
 | 177 | do_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 |  | 
 | 192 | int | 
 | 193 | Perforce::EditFiles(const vector<string>& files, bool printOnFailure) | 
 | 194 | { | 
 | 195 |     return do_files("edit", files, printOnFailure); | 
 | 196 | } | 
 | 197 |  | 
 | 198 | int | 
 | 199 | Perforce::AddFiles(const vector<string>& files, bool printOnFailure) | 
 | 200 | { | 
 | 201 |     return do_files("add", files, printOnFailure); | 
 | 202 | } | 
 | 203 |  | 
 | 204 | int | 
 | 205 | Perforce::DeleteFiles(const vector<string>& files, bool printOnFailure) | 
 | 206 | { | 
 | 207 |     return do_files("delete", files, printOnFailure); | 
 | 208 | } | 
 | 209 |  | 
 | 210 | string | 
 | 211 | Perforce::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 |  |