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