| package org.eclipse.europa.tools.webgen; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.FileReader; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| public class LogFileParser { |
| public BufferedReader input; |
| |
| public List<ProjectLog> projects; |
| public List<LogLine> lines; |
| public Status status; |
| |
| public LogFileParser(File f) throws IOException { |
| input = new BufferedReader(new FileReader(f)); |
| } |
| |
| public void parse() throws IOException { |
| read_all_lines_into_memory(); |
| divide_into_projects(); |
| for (Iterator<ProjectLog> iterator = projects.iterator(); iterator |
| .hasNext();) { |
| ProjectLog project = iterator.next(); |
| project.divide_into_features(); |
| } |
| } |
| |
| void scan_for_status() throws IOException { |
| this.status = Status.unknown; |
| for (Iterator<ProjectLog> iterator = projects.iterator(); iterator |
| .hasNext();) { |
| ProjectLog project = iterator.next(); |
| project.scan_for_status(); |
| this.status = this.status.combine(project.status); |
| } |
| if (this.status.isFail()) |
| this.status = Status.fail; |
| } |
| |
| void read_all_lines_into_memory() throws IOException { |
| lines = new ArrayList<LogLine>(); |
| String line = input.readLine(); |
| int num = 1; |
| while (line != null) { |
| LogLine logline = new LogLine(line, num++); |
| lines.add(logline); |
| line = input.readLine(); |
| } |
| } |
| |
| void divide_into_projects() { |
| /* |
| * This algorithm works by looking through the lines of the log |
| * file for special marker lines. In general, it keeps three pointers: |
| * |
| * ... |
| * ... |
| * ... <-- start (of the project I'm currently scanning) |
| * ... \ |
| * ... |<-- (body of the project I'm currently scanning) |
| * ... / |
| * ... <-- potential_end (of the project I'm currently scanning) |
| * ... \ |
| * ... |<-- (body of the next project) |
| * ... / |
| * ... <-- line_number (the current line) |
| * |
| * This is because we don't know we're in a new project until we encounter |
| * the "Project:" header, but at the same time the beginning of the new |
| * project is the previous "update:" line before the Project: line. |
| */ |
| projects = new ArrayList<ProjectLog>(); |
| ProjectLog current = new ProjectLog("prefix", ""); |
| projects.add(current); |
| Pattern p1 = Pattern |
| .compile("\\[echo\\]\\s+\\-*\\s+Project:\\s+([\\w\\s_\\-\\.,]+)\\s+Responsible:\\s+(\\w+)"); |
| Pattern p2 = Pattern.compile("update:"); |
| Pattern p3 = Pattern.compile("^Total time:"); |
| int start_of_current_project = 0; |
| int potential_end = 0; |
| Iterator<LogLine> iter = lines.iterator(); |
| int line_number = 0; |
| while (iter.hasNext()) { |
| LogLine line = iter.next(); |
| Matcher m1 = p1.matcher(line.line); |
| Matcher m2 = p2.matcher(line.line); |
| Matcher m3 = p3.matcher(line.line); |
| /* |
| * If we've found a "Project:" line then we need |
| * to start a new project section. |
| */ |
| if (m1.find()) { |
| /* special case for the first project in the file: |
| * we haven't seen the end of the previous project yet (because |
| * there isn't one), so the Project: line be the "end" of the |
| * non-existent previous project */ |
| if (start_of_current_project == potential_end) |
| potential_end = line_number; |
| /* save away the lines for the current project, i.e., |
| * the one we were collecting for, not the one for which |
| * we've just seen the start line */ |
| current.lines = lines.subList(start_of_current_project, potential_end); |
| /* the start of the next project section is the end |
| * of the current one */ |
| start_of_current_project = potential_end; |
| /* the end of the next project cannot be earlier than |
| * it's beginning, so set it as well */ |
| potential_end = start_of_current_project; |
| /* start a new project with the new name, etc. |
| * We are now scanning lines for this project. */ |
| current = new ProjectLog(m1.group(1), m1.group(2)); |
| projects.add(current); |
| } |
| /* |
| * If we've found "update:" then it marks the potential |
| * end to the current project. We won't know that until |
| * we find a "Project:" line, but we record it as a |
| * potential end here. |
| */ |
| if (m2.matches() ) |
| potential_end = line_number; |
| /* |
| * If we've found "Total time:" then the NEXT line is |
| * the potential end to the current project. Again, we |
| * won't know that until... |
| */ |
| if (m3.find() ) |
| potential_end = line_number + 1; |
| line_number++; |
| } |
| potential_end = line_number; |
| current.lines = lines.subList(start_of_current_project, potential_end); |
| } |
| } |