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