bool Mal4sLog::parseCommitEntry(RCommit& commit) { std::string line; std::vector<std::string> entries; if(!getNextLine(line)) return false; //custom line if(!mal4s_regex.match(line, &entries)) return false; long timestamp = atol(entries[0].c_str()); std::string username = (entries[1].size()>0) ? entries[1] : "Unknown"; std::string action = (entries[2].size()>0) ? entries[2] : "A"; //if this file is for the same person and timestamp //we add to the commit, else we save the lastline //and return false if(commit.files.empty()) { commit.timestamp = timestamp; commit.username = username; } else { if(commit.timestamp != timestamp || commit.username != username) { lastline = line; return false; } } if(entries.size()>=6 && entries[5].size()>0) { commit.userimagename = entries[5]; } else commit.userimagename = commit.username; std::vector<std::string> displayData; //Extra fields for display on hover. if(entries.size()>=7 ) { displayData = split(entries[6], '|'); } bool has_colour = false; vec3 colour; if(entries.size()>=5 && entries[4].size()>0) { has_colour = true; colour = parseColour(entries[4]); } if(has_colour) { commit.addFile(entries[3], action, colour, commit.username, commit.userimagename, displayData); } else { commit.addFile(entries[3], action, commit.username, commit.userimagename, displayData); } return true; }
bool CustomLog::readCustomCommit(RCommit& commit) { std::string line; std::vector<std::string> entries; if(!getNextLine(line)) return false; //custom line if(!custom_regex.match(line, &entries)) return false; long timestamp = atol(entries[0].c_str()); std::string username = (entries[1].size()>0) ? entries[1] : "Unknown"; std::string action = (entries[2].size()>0) ? entries[2] : "A"; bool has_colour = false; vec3f colour; if(entries.size()>=5 && entries[4].size()>0) { has_colour = true; colour = parseColour(entries[4]); } //if this file is for the same person and timestamp //we add to the commit, else we save the lastline //and return false if(commit.files.size() > 0 && (commit.timestamp != timestamp || commit.username != username)) { lastline = line; return false; } if(commit.files.size() == 0) { commit.timestamp = timestamp; commit.username = username; } if(has_colour) { commit.addFile(entries[3], action, colour); } else { commit.addFile(entries[3], action); } return true; }
bool CustomLog::parseCommit(RCommit& commit) { std::string line; std::vector<std::string> entries; if(!logf->getNextLine(line)) return false; //custom line if(!custom_regex.match(line, &entries)) return false; commit.timestamp = atol(entries[0].c_str()); commit.username = entries[1]; if(commit.username.size()==0) { commit.username = "******"; } std::string action = "A"; if(entries[2].size()>0) { action = entries[2]; } bool has_colour = false; vec3f colour; if(entries.size()>=5 && entries[4].size()>0) { has_colour = true; colour = parseColour(entries[4]); } // debugLog("file = %s, timestamp=%d, username=%s, action=%s\n", entries[3].c_str(), // commit.timestamp, commit.username.c_str(), action.c_str()); if(has_colour) { commit.addFile(entries[3], action, colour); } else { commit.addFile(entries[3], action); } //commit.debug(); return true; }
bool RCommitLog::nextCommit(RCommit& commit, bool validate) { if(buffered) { commit = lastCommit; buffered = false; return true; } bool success = parseCommit(commit); if(!success) return false; commit.postprocess(); if(validate) return commit.isValid(); return true; }
bool GitRawCommitLog::parseCommit(RCommit& commit) { std::string line; std::vector<std::string> entries; //read commit ref/ branch if(!logf->getNextLine(line)) return false; //commit if(!git_raw_commit.match(line, &entries)) return false; if(!logf->getNextLine(line)) return false; //tree if(!git_raw_tree.match(line, &entries)) return false; if(!logf->getNextLine(line)) return false; //0 or more parents while(git_raw_parent.match(line, &entries)) { if(!logf->getNextLine(line)) return false; } //author - used for display name if(!git_raw_author.match(line, &entries)) return false; commit.username = entries[0]; if(!logf->getNextLine(line)) return false; //committer - used for time (most likely cronological) if(!git_raw_committer.match(line, &entries)) return false; commit.timestamp = atol(entries[3].c_str()); //blank line before message if(!logf->getNextLine(line)) return false; //read commit message while(logf->getNextLine(line) && line.size()) { } //read files while(logf->getNextLine(line) && line.size()) { //debugLog("file??? %s\n", line.c_str()); if(git_raw_file.match(line, &entries)) { commit.addFile(entries[2], entries[1]); } } // commit.debug(); return true; }
bool GitCommitLog::parseCommit(RCommit& commit) { std::string line; commit.username = ""; while(logf->getNextLine(line) && line.size()) { if(line.find("user:"******"') == 0 && file.rfind('"') == file.size()-1) { if(file.size()<=2) continue; file = file.substr(1,file.size()-2); } commit.addFile(file, status); } //check we at least got a username if(commit.username.size()==0) return false; return true; }
bool RCommitLog::nextCommit(RCommit& commit) { if(buffered) { commit = lastCommit; buffered = false; return true; } bool success = parseCommit(commit); if(!success) return false; return commit.isValid(); }
bool GitCommitLog::parseCommit(RCommit& commit) { std::string line; //read author name if(!logf->getNextLine(line)) return false; //ensure username prefixed with user: otherwise the log is not in //the expected format and we can try a different format if(line.size() < 6 || line.find("user:") != 0) { return false; } //username follows user prefix commit.username = line.substr(5); if(!logf->getNextLine(line)) return false; //committer time - used instead of author time (most likely cronological) // NOTE: ignoring timezone ... commit.timestamp = atol(line.c_str()); //this isnt a commit we are parsing, abort if(commit.timestamp == 0) return false; //read files while(logf->getNextLine(line) && line.size()) { size_t tab = line.find('\t'); if(tab == std::string::npos) continue; //incorrect log format if(tab == 0 || tab == line.size()-1) return false; std::string status = line.substr(tab - 1, 1); line = line.substr(tab + 1); commit.addFile(line, status); } //commit.debug(); return true; }
bool BazaarLog::parseCommit(RCommit& commit) { std::string line; std::vector<std::string> entries; int year, month, day; if(!logf->getNextLine(line)) return false; debugLog("read %s\n", line.c_str()); if (!bzr_commit_regex.match(line, &entries)) { debugLog("regex failed\n"); return false; } commit.username = entries[1]; year = atoi(entries[2].c_str()); month = atoi(entries[3].c_str()); day = atoi(entries[4].c_str()); struct tm time_str; time_str.tm_year = year - 1900; time_str.tm_mon = month - 1; time_str.tm_mday = day; time_str.tm_hour = 0; time_str.tm_min = 0; time_str.tm_sec = 0; time_str.tm_isdst = -1; commit.timestamp = mktime(&time_str); while(logf->getNextLine(line) && line.size()) { if (!bzr_file_regex.match(line, &entries)) continue; commit.addFile(entries[1], entries[0]); } return true; }
bool MercurialLog::parseCommitEntry(RCommit& commit) { std::string line; std::vector<std::string> entries; if(!logf->getNextLine(line)) return false; //custom line if(!hg_regex.match(line, &entries)) return false; time_t timestamp = atol(entries[0].c_str()); std::string username = entries[1]; //if this file is for the same person and timestamp //we add to the commit, else we save the lastline //and return false if(commit.files.empty()) { commit.timestamp = timestamp; commit.username = username; } else { if(commit.timestamp != timestamp || commit.username != username) { lastline = line; return false; } } std::string action = "A"; if(!entries[2].empty()) { action = entries[2]; } commit.addFile(entries[3], action); //commit.debug(); return true; }
bool SVNCommitLog::parseCommit(RCommit& commit) { //fprintf(stderr,"parsing svn log\n"); std::string line; if(!getNextLine(line)) return false; //start of log entry if(!svn_logentry_start.match(line)) { //is this the start of the document if(!svn_xml_tag.match(line)) return false; //fprintf(stderr,"found xml tag\n"); //if so find the first logentry tag bool found_logentry = false; while(getNextLine(line)) { if(svn_logentry_start.match(line)) { found_logentry = true; break; } } if(!found_logentry) return false; } //fprintf(stderr,"found logentry\n"); logentry.clear(); logentry.append(line); logentry.append("\n"); //fprintf(stderr,"found opening tag\n"); bool endfound = false; while(getNextLine(line)) { logentry.append(line); logentry.append("\n"); if(svn_logentry_end.match(line)) { //fprintf(stderr,"found closing tag\n"); endfound=true; break; } } //incomplete commit if(!endfound) return false; //fprintf(stderr,"read logentry\n"); TiXmlDocument doc; if(!doc.Parse(logentry.c_str())) return false; //fprintf(stderr,"try to parse logentry: %s\n", logentry.c_str()); TiXmlElement* leE = doc.FirstChildElement( "logentry" ); std::vector<std::string> entries; if(!leE) return false; //parse date TiXmlElement* dateE = leE->FirstChildElement( "date" ); if(!dateE) return false; std::string timestamp_str(dateE->GetText()); if(!svn_logentry_timestamp.match(timestamp_str, &entries)) return false; struct tm time_str; time_str.tm_year = atoi(entries[0].c_str()) - 1900; time_str.tm_mon = atoi(entries[1].c_str()) - 1; time_str.tm_mday = atoi(entries[2].c_str()); time_str.tm_hour = atoi(entries[3].c_str()); time_str.tm_min = atoi(entries[4].c_str()); time_str.tm_sec = atoi(entries[5].c_str()); time_str.tm_isdst = -1; #ifdef HAVE_TIMEGM commit.timestamp = timegm(&time_str); #else commit.timestamp = __timegm_hack(&time_str); #endif //parse author TiXmlElement* authorE = leE->FirstChildElement("author"); if(authorE != 0) { // GetText() may return NULL, causing author instantiation to crash. std::string author(authorE->GetText() ? authorE->GetText() : "Unknown"); if(author.empty()) author = "Unknown"; commit.username = author; } TiXmlElement* pathsE = leE->FirstChildElement( "paths" ); //log entries sometimes dont have any paths if(!pathsE) return true; //parse changes for(TiXmlElement* pathE = pathsE->FirstChildElement("path"); pathE != 0; pathE = pathE->NextSiblingElement()) { //parse path const char* kind = pathE->Attribute("kind"); const char* action = pathE->Attribute("action"); //check for action if(action == 0) continue; bool is_dir = false; //if has the 'kind' attribute (old versions of svn dont have this), check if it is a dir if(kind != 0 && strcmp(kind,"dir") == 0) { //accept only deletes for directories if(strcmp(action, "D") != 0) continue; is_dir = true; } std::string file(pathE->GetText()); std::string status(action); if(file.empty()) continue; if(status.empty()) continue; //append trailing slash if is directory if(is_dir && file[file.size()-1] != '/') { file = file + std::string("/"); } commit.addFile(file, status); } //fprintf(stderr,"parsed logentry\n"); //read files return true; }
bool CVSEXPCommitLog::parseCommit(RCommit& commit) { std::string line; std::vector<std::string> entries; if(!logf->getNextLine(line)) return false; //skip empty line if there is one if(line.size() == 0) { if(!logf->getNextLine(line)) return false; } //read commit no if(!cvsexp_commitno_regex.match(line, &entries)) return false; int commitno = atoi(entries[0].c_str()); //debugLog("commitno matched\n"); if(!logf->getNextLine(line)) return false; //should be a branch if(cvsexp_branch_regex.match(line, &entries)) { //commit.addBranch(entries[0]); //read next blank line if(!logf->getNextLine(line)) return false; if(line.size()) return false; if(!logf->getNextLine(line)) return false; } //parse date if(!cvsexp_date_regex.match(line, &entries)) return false; //debugLog("date matched\n"); struct tm time_str; time_str.tm_year = atoi(entries[0].c_str()) - 1900; time_str.tm_mon = atoi(entries[1].c_str()) - 1; time_str.tm_mday = atoi(entries[2].c_str()); time_str.tm_hour = atoi(entries[3].c_str()); time_str.tm_min = atoi(entries[4].c_str()); time_str.tm_sec = atoi(entries[5].c_str()); time_str.tm_isdst = -1; commit.timestamp = mktime(&time_str); //parse author,state std::string rest = entries[6]; if(!cvsexp_detail_regex.match(rest, &entries)) return false; //debugLog("author/state matched\n"); commit.username = entries[0]; std::string commit_state = entries[1]; //if rest is not ')' parse lines rest = entries[2]; // need to parse lines if(rest.size() > 2) { if(!cvsexp_lines_regex.match(rest, &entries)) return false; } if(!logf->getNextLine(line)) return false; std::string commit_action = (commit_state == "dead") ? "D" : "M"; while(cvsexp_entry_regex.match(line, &entries)) { //ignore files in Attic - previously deleted file if(entries[0].find("/Attic/") == std::string::npos) { commit.addFile(entries[0], commit_action); } if(!logf->getNextLine(line)) return false; } //read blank line if(!logf->getNextLine(line)) return false; //std::string message; //read commit message while(logf->getNextLine(line) && line.size()) { //if(message.size()) message += std::string("\n"); //message += line; } //read until end of commit or eof while(logf->getNextLine(line)) { if(cvsexp_end_regex.match(line,&entries)) { //debugLog("read end of commit %s\n", entries[0].c_str()); break; } } return true; }
bool CVS2CLCommitLog::parseCommit(RCommit& commit) { //fprintf(stderr,"parsing cvs2cl log\n"); std::string line; if(!getNextLine(line)) return false; //start of log entry if(!cvs2cl_logentry_start.match(line)) { //is this the start of the document if(!cvs2cl_xml_tag.match(line)) return false; //fprintf(stderr,"found xml tag\n"); //if so find the first logentry tag bool found_logentry = false; while(getNextLine(line)) { if(cvs2cl_logentry_start.match(line)) { found_logentry = true; break; } } if(!found_logentry) return false; } //fprintf(stderr,"found logentry\n"); logentry.clear(); logentry.append(line); logentry.append("\n"); //fprintf(stderr,"found opening tag\n"); bool endfound = false; while(getNextLine(line)) { logentry.append(line); logentry.append("\n"); if(cvs2cl_logentry_end.match(line)) { //fprintf(stderr,"found closing tag\n"); endfound=true; break; } } //incomplete commit if(!endfound) return false; //fprintf(stderr,"read logentry\n"); TiXmlDocument doc; if(!doc.Parse(logentry.c_str())) return false; //fprintf(stderr,"try to parse logentry: %s\n", logentry.c_str()); TiXmlElement* leE = doc.FirstChildElement( "entry" ); std::vector<std::string> entries; if(!leE) return false; //parse date TiXmlElement* dateE = leE->FirstChildElement( "isoDate" ); if(!dateE) return false; std::string timestamp_str(dateE->GetText()); if(!cvs2cl_logentry_timestamp.match(timestamp_str, &entries)) return false; struct tm time_str; time_str.tm_year = atoi(entries[0].c_str()) - 1900; time_str.tm_mon = atoi(entries[1].c_str()) - 1; time_str.tm_mday = atoi(entries[2].c_str()); time_str.tm_hour = atoi(entries[3].c_str()); time_str.tm_min = atoi(entries[4].c_str()); time_str.tm_sec = atoi(entries[5].c_str()); time_str.tm_isdst = -1; commit.timestamp = mktime(&time_str); //parse author TiXmlElement* authorE = leE->FirstChildElement("author"); if(authorE != 0) { std::string author(authorE->GetText()); if(author.empty()) author = "Unknown"; commit.username = author; } //parse changes for(TiXmlElement* fileE = leE->FirstChildElement("file"); fileE != 0; fileE = fileE->NextSiblingElement()) { TiXmlElement* state = fileE->FirstChildElement("cvsstate"); TiXmlElement* name = fileE->FirstChildElement("name"); //check for state if(name == 0 || state == 0) continue; std::string status = strcmp(state->GetText(), "dead") == 0 ? "D" : "M"; std::string file(name->GetText()); if(file.empty()) continue; commit.addFile(file, status); } //fprintf(stderr,"parsed logentry\n"); //read files return true; }
//parse apache access.log entry into components bool ApacheCombinedLog::parseCommit(RCommit& commit) { std::string line; std::vector<std::string> matches; if(!logf->getNextLine(line)) return false; apache_entry_start.match(line, &matches); if(matches.size()!=4) { return 0; } //get details commit.username = matches[0]; //std::string user = matches[1]; //parse timestamp struct tm time_str; std::string request_str = matches[3]; std::string datestr = matches[2]; apache_entry_date.match(datestr, &matches); if(matches.size()!=8) { return 0; } int day = atoi(matches[0].c_str()); int year = atoi(matches[2].c_str()); int hour = atoi(matches[3].c_str()); int minute = atoi(matches[4].c_str()); int second = atoi(matches[5].c_str()); // int zone = atoi(matches[7].c_str()); //negative timezone // if(strcmp(matches[6].c_str(), "-")==0) { // zone = -zone; // } int month=0; for(int i=0;i<12;i++) { if(matches[1] == months[i]) { month=i; break; } } time_str.tm_year = year - 1900; time_str.tm_mon = month; time_str.tm_mday = day; time_str.tm_hour = hour; time_str.tm_min = minute; time_str.tm_sec = second; time_str.tm_isdst = -1; commit.timestamp = mktime(&time_str); matches.clear(); apache_entry_request.match(request_str, &matches); if(matches.size() < 5) { return false; } std::string rtype = matches[0]; std::string file = matches[1]; std::string proto = matches[2]; int code = atoi(matches[3].c_str()); int bytes = atol(matches[4].c_str()); //remove args from url int argpos = file.rfind("?"); if(argpos != std::string::npos) { file = file.substr(0,argpos); } if(file.size()==0) file = "/"; //name index pages if(file[file.size()-1] == '/') { file += "index.html"; } std::string action = "A"; commit.addFile(file, action); std::string refer; std::string agent; if(matches.size() > 5) { std::string agentstr = matches[5]; matches.clear(); apache_entry_agent.match(agentstr, &matches); if(matches.size()>1) { refer = matches[0]; agent = matches[1]; } } return true; }
bool GitCommitLog::parseCommit(RCommit& commit) { std::string line; char filesizeBuf[256]; commit.username = ""; while(logf->getNextLine(line) && line.size()) { if(line.find("commit_id:") == 0) { commit.commit_id = line.substr(10); if(!logf->getNextLine(line)) return false; //username follows user prefix commit.username = line.substr(5); if(!logf->getNextLine(line)) return false; commit.timestamp = atol(line.c_str()); //this isnt a commit we are parsing, abort if(commit.timestamp == 0) return false; continue; } //should see username before files if(commit.username.empty()) return false; size_t tab = line.find('\t'); //incorrect log format if(tab == std::string::npos || tab == 0 || tab == line.size()-1) continue; std::string status = line.substr(tab - 1, 1); std::string file = line.substr(tab + 1); if(file.empty()) continue; //check for and remove double quotes if(file.find('"') == 0 && file.rfind('"') == file.size()-1) { if(file.size()<=2) continue; file = file.substr(1,file.size()-2); } std::string size_temp_file = temp_file + "_filesize"; memset(filesizeBuf, 0, sizeof(char) * 256); snprintf(filesizeBuf, sizeof(char) * 256, GitGetFileSizeCommand.c_str(), commit.commit_id.c_str(), file.c_str(), size_temp_file.c_str()); systemCommand(filesizeBuf); std::ifstream ifs ( size_temp_file ); std::string filesize_str; ifs >> filesize_str; size_t filesize = 0; if(!filesize_str.empty()) { filesize = std::stoi(filesize_str); } commit.addFile(file, status, filesize); } //check we at least got a username if(commit.username.empty()) return false; return true; }