235 lines
4.9 KiB
C++
235 lines
4.9 KiB
C++
|
#include "Perforce.h"
|
||
|
#include "log.h"
|
||
|
#include <string.h>
|
||
|
#include <cstdio>
|
||
|
#include <stdlib.h>
|
||
|
#include <sstream>
|
||
|
#include <sys/types.h>
|
||
|
#include <unistd.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <sys/wait.h>
|
||
|
#include <cstdio>
|
||
|
|
||
|
using namespace std;
|
||
|
|
||
|
extern char** environ;
|
||
|
|
||
|
int
|
||
|
Perforce::RunCommand(const string& cmd, string* result, bool printOnFailure)
|
||
|
{
|
||
|
int err;
|
||
|
int outPipe[2];
|
||
|
int errPipe[2];
|
||
|
pid_t pid;
|
||
|
|
||
|
log_printf("Perforce::RunCommand: %s\n", cmd.c_str());
|
||
|
|
||
|
err = pipe(outPipe);
|
||
|
err |= pipe(errPipe);
|
||
|
if (err == -1) {
|
||
|
printf("couldn't create pipe. exiting.\n");
|
||
|
exit(1);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
pid = fork();
|
||
|
if (pid == -1) {
|
||
|
printf("couldn't fork. eixiting\n");
|
||
|
exit(1);
|
||
|
return -1;
|
||
|
}
|
||
|
else if (pid == 0) {
|
||
|
char const* args[] = {
|
||
|
"/bin/sh",
|
||
|
"-c",
|
||
|
cmd.c_str(),
|
||
|
NULL
|
||
|
};
|
||
|
close(outPipe[0]);
|
||
|
close(errPipe[0]);
|
||
|
dup2(outPipe[1], 1);
|
||
|
dup2(errPipe[1], 2);
|
||
|
execve(args[0], (char* const*)args, environ);
|
||
|
// done
|
||
|
}
|
||
|
|
||
|
close(outPipe[1]);
|
||
|
close(errPipe[1]);
|
||
|
|
||
|
result->clear();
|
||
|
|
||
|
char buf[1024];
|
||
|
|
||
|
// stdout
|
||
|
while (true) {
|
||
|
size_t amt = read(outPipe[0], buf, sizeof(buf));
|
||
|
result->append(buf, amt);
|
||
|
if (amt <= 0) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// stderr -- the messages are short so it ought to just fit in the buffer
|
||
|
string error;
|
||
|
while (true) {
|
||
|
size_t amt = read(errPipe[0], buf, sizeof(buf));
|
||
|
error.append(buf, amt);
|
||
|
if (amt <= 0) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
close(outPipe[0]);
|
||
|
close(errPipe[0]);
|
||
|
|
||
|
waitpid(pid, &err, 0);
|
||
|
if (WIFEXITED(err)) {
|
||
|
err = WEXITSTATUS(err);
|
||
|
} else {
|
||
|
err = -1;
|
||
|
}
|
||
|
if (err != 0 && printOnFailure) {
|
||
|
write(2, error.c_str(), error.length());
|
||
|
}
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
Perforce::GetResourceFileNames(const string& version, const string& base,
|
||
|
const vector<string>& apps, vector<string>* results,
|
||
|
bool printOnFailure)
|
||
|
{
|
||
|
int err;
|
||
|
string text;
|
||
|
stringstream cmd;
|
||
|
|
||
|
cmd << "p4 files";
|
||
|
|
||
|
const size_t I = apps.size();
|
||
|
for (size_t i=0; i<I; i++) {
|
||
|
cmd << " \"" << base << '/' << apps[i] << "/res/values/strings.xml@" << version << '"';
|
||
|
}
|
||
|
|
||
|
err = RunCommand(cmd.str(), &text, printOnFailure);
|
||
|
|
||
|
const char* str = text.c_str();
|
||
|
while (*str) {
|
||
|
const char* lineend = strchr(str, '\n');
|
||
|
if (lineend == str) {
|
||
|
str++;
|
||
|
continue;
|
||
|
}
|
||
|
if (lineend-str > 1023) {
|
||
|
fprintf(stderr, "line too long!\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
string s(str, lineend-str);
|
||
|
|
||
|
char filename[1024];
|
||
|
char edit[1024];
|
||
|
int count = sscanf(str, "%[^#]#%*d - %s change %*d %*[^\n]\n", filename, edit);
|
||
|
|
||
|
if (count == 2 && 0 != strcmp("delete", edit)) {
|
||
|
results->push_back(string(filename));
|
||
|
}
|
||
|
|
||
|
str = lineend + 1;
|
||
|
}
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
Perforce::GetFile(const string& file, const string& version, string* result,
|
||
|
bool printOnFailure)
|
||
|
{
|
||
|
stringstream cmd;
|
||
|
cmd << "p4 print -q \"" << file << '@' << version << '"';
|
||
|
return RunCommand(cmd.str(), result, printOnFailure);
|
||
|
}
|
||
|
|
||
|
string
|
||
|
Perforce::GetCurrentChange(bool printOnFailure)
|
||
|
{
|
||
|
int err;
|
||
|
string text;
|
||
|
|
||
|
err = RunCommand("p4 changes -m 1 \\#have", &text, printOnFailure);
|
||
|
if (err != 0) {
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
long long n;
|
||
|
int count = sscanf(text.c_str(), "Change %lld on", &n);
|
||
|
if (count != 1) {
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
char result[100];
|
||
|
sprintf(result, "%lld", n);
|
||
|
|
||
|
return string(result);
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
do_files(const string& op, const vector<string>& files, bool printOnFailure)
|
||
|
{
|
||
|
string text;
|
||
|
stringstream cmd;
|
||
|
|
||
|
cmd << "p4 " << op;
|
||
|
|
||
|
const size_t I = files.size();
|
||
|
for (size_t i=0; i<I; i++) {
|
||
|
cmd << " \"" << files[i] << "\"";
|
||
|
}
|
||
|
|
||
|
return Perforce::RunCommand(cmd.str(), &text, printOnFailure);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
Perforce::EditFiles(const vector<string>& files, bool printOnFailure)
|
||
|
{
|
||
|
return do_files("edit", files, printOnFailure);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
Perforce::AddFiles(const vector<string>& files, bool printOnFailure)
|
||
|
{
|
||
|
return do_files("add", files, printOnFailure);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
Perforce::DeleteFiles(const vector<string>& files, bool printOnFailure)
|
||
|
{
|
||
|
return do_files("delete", files, printOnFailure);
|
||
|
}
|
||
|
|
||
|
string
|
||
|
Perforce::Where(const string& depotPath, bool printOnFailure)
|
||
|
{
|
||
|
int err;
|
||
|
string text;
|
||
|
string cmd = "p4 where ";
|
||
|
cmd += depotPath;
|
||
|
|
||
|
err = RunCommand(cmd, &text, printOnFailure);
|
||
|
if (err != 0) {
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
size_t index = text.find(' ');
|
||
|
if (index == text.npos) {
|
||
|
return "";
|
||
|
}
|
||
|
index = text.find(' ', index+1)+1;
|
||
|
if (index == text.npos) {
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
return text.substr(index, text.length()-index-1);
|
||
|
}
|
||
|
|