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