1 #include "Perforce.h"
2 #include "log.h"
3 #include <string.h>
4 #include <cstdio>
5 #include <stdlib.h>
6 #include <sstream>
7 #include <sys/types.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/wait.h>
12 #include <cstdio>
13
14 using namespace std;
15
16 extern char** environ;
17
18 int
RunCommand(const string & cmd,string * result,bool printOnFailure)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
GetResourceFileNames(const string & version,const string & base,const vector<string> & apps,vector<string> * results,bool printOnFailure)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
GetFile(const string & file,const string & version,string * result,bool printOnFailure)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
GetCurrentChange(bool printOnFailure)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
do_files(const string & op,const vector<string> & files,bool printOnFailure)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
EditFiles(const vector<string> & files,bool printOnFailure)193 Perforce::EditFiles(const vector<string>& files, bool printOnFailure)
194 {
195 return do_files("edit", files, printOnFailure);
196 }
197
198 int
AddFiles(const vector<string> & files,bool printOnFailure)199 Perforce::AddFiles(const vector<string>& files, bool printOnFailure)
200 {
201 return do_files("add", files, printOnFailure);
202 }
203
204 int
DeleteFiles(const vector<string> & files,bool printOnFailure)205 Perforce::DeleteFiles(const vector<string>& files, bool printOnFailure)
206 {
207 return do_files("delete", files, printOnFailure);
208 }
209
210 string
Where(const string & depotPath,bool printOnFailure)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
235