blob: a7f301e4072d8c515adaf8546e9aeaeb0f583d31 [file] [log] [blame]
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001#include "Perforce.h"
2#include "log.h"
The Android Open Source Projectb7986892009-01-09 17:51:23 -08003#include <string.h>
4#include <stdlib.h>
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07005#include <sstream>
6#include <sys/types.h>
7#include <unistd.h>
Alexey Zaytsev862bfdb2008-10-22 02:05:55 +04008#include <stdlib.h>
9#include <string.h>
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070010#include <sys/wait.h>
Scott Tsai8a2b9082009-03-21 08:08:36 +080011#include <cstdio>
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070012
13using namespace std;
14
15extern char** environ;
16
17int
18Perforce::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
97int
98Perforce::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
143int
144Perforce::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
152string
153Perforce::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
175static int
176do_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
191int
192Perforce::EditFiles(const vector<string>& files, bool printOnFailure)
193{
194 return do_files("edit", files, printOnFailure);
195}
196
197int
198Perforce::AddFiles(const vector<string>& files, bool printOnFailure)
199{
200 return do_files("add", files, printOnFailure);
201}
202
203int
204Perforce::DeleteFiles(const vector<string>& files, bool printOnFailure)
205{
206 return do_files("delete", files, printOnFailure);
207}
208
209string
210Perforce::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