Back to index

lightning-sunbird  0.9+nobinonly
BlameTable.java
Go to the documentation of this file.
00001 /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * The contents of this file are subject to the Netscape Public
00004  * License Version 1.1 (the "License"); you may not use this file
00005  * except in compliance with the License. You may obtain a copy of
00006  * the License at http://www.mozilla.org/NPL/
00007  *
00008  * Software distributed under the License is distributed on an "AS
00009  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
00010  * implied. See the License for the specific language governing
00011  * rights and limitations under the License.
00012  *
00013  * The Original Code is Mozilla Communicator client code, released
00014  * March 31, 1998.
00015  *
00016  * The Initial Developer of the Original Code is Netscape
00017  * Communications Corporation.  Portions created by Netscape are
00018  * Copyright (C) 1998 Netscape Communications Corporation. All
00019  * Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Patrick C. Beard <beard@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the
00026  * terms of the GNU Public License (the "GPL"), in which case the
00027  * provisions of the GPL are applicable instead of those above.
00028  * If you wish to allow use of your version of this file only
00029  * under the terms of the GPL and not to allow others to use your
00030  * version of this file under the NPL, indicate your decision by
00031  * deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL.  If you do not delete
00033  * the provisions above, a recipient may use your version of this
00034  * file under either the NPL or the GPL.
00035  */
00036 
00037 import java.io.*;
00038 import java.util.*;
00039 import java.net.*;
00040 
00041 class Blame {
00042        String[] lines;
00043        Hashtable info;
00044        
00045        Blame(String[] lines, Hashtable info) {
00046               this.lines = lines;
00047               this.info = info;
00048        }
00049 }
00050 
00051 public class BlameTable {
00052        private Hashtable blameTable = new Hashtable();
00053        
00054        public String getBlame(String bonsaiPath, int line) {
00055               Blame blame = (Blame) blameTable.get(bonsaiPath);
00056               if (blame == null) {
00057                      blame = assignBlame(bonsaiPath);
00058                      blameTable.put(bonsaiPath, blame);
00059               }
00060               if (blame != null) {
00061                      String[] lines = blame.lines;
00062                      if (line > 0 && lines.length > 0 && line <= lines.length)
00063                             return (String) blame.info.get(lines[line - 1]);
00064               }
00065               return "error";
00066        }
00067        
00068        static final String CVSBLAME_CGI = "http://bonsai.mozilla.org/cvsblame.cgi?data=1&file=";
00069 
00070        private static int parseInt(String str) {
00071               int value = 0;
00072               try {
00073                      value = Integer.parseInt(str);
00074               } catch (NumberFormatException nfe) {
00075               }
00076               return value;
00077        }
00078 
00082        static String quoteTags(StringBuffer buf) {
00083               int length = buf.length();
00084               for (int i = 0; i < length; ++i) {
00085                      char ch = buf.charAt(i);
00086                      switch (ch) {
00087                      case '<':
00088                             buf.setCharAt(i, '&');
00089                             buf.insert(i + 1, "LT;");
00090                             i += 4;
00091                             length += 3;
00092                             break;
00093                      case '>':
00094                             buf.setCharAt(i, '&');
00095                             buf.insert(i + 1, "GT;");
00096                             i += 4;
00097                             length += 3;
00098                             break;
00099                      }
00100               }
00101               return buf.toString();
00102        }
00103 
00108        private Blame assignBlame(String bonsaiPath) {
00109               try {
00110                      Vector vec = new Vector();
00111                      URL url = new URL(CVSBLAME_CGI + bonsaiPath);
00112                      BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
00113                      
00114                      // read revision for each line of the file. this is really slow. I asked slam to
00115                      // use buffered output, to speed this up.
00116                      for (String line = reader.readLine(); line != null; line = reader.readLine()) {
00117                             if (line.charAt(0) == 'R')
00118                                    break;
00119                             // decompress "revision:count" to simplify getBlame() above.
00120                             int colonIndex = line.indexOf(':');
00121                             String revision = line.substring(0, colonIndex);
00122                             int count = parseInt(line.substring(colonIndex + 1));
00123                             while (count-- > 0)
00124                                    vec.addElement(revision);
00125                      }
00126                      String[] lines = new String[vec.size()];
00127                      vec.copyInto(lines);
00128                      vec.removeAllElements();
00129 
00130                      // read revision records, which are of the form "rev|date|who|comment" where comment can span multiple lines,
00131                      // and each record is terminated by a "." on its own line.
00132                      Hashtable info = new Hashtable();
00133                      String revision = null;
00134                      StringBuffer buffer = new StringBuffer();
00135                      for (String line = reader.readLine(); line != null; line = reader.readLine()) {
00136                             // we're in one of two states, either we've seen a line starting with a revision,
00137                             // and we're waiting for the final ending line, or we're starting a new revision
00138                             // record.
00139                             if (revision != null) {
00140                                    if (line.equals(".")) {
00141                                           // end of current revision record.
00142                                           info.put(revision, quoteTags(buffer));
00143                                           revision = null;
00144                                           buffer.setLength(0);
00145                                    } else {
00146                                           // continuation of a comment
00147                                           buffer.append(" " + line);
00148                                    }
00149                             } else {
00150                                    int orIndex = line.indexOf('|');
00151                                    if (orIndex >= 0) {
00152                                           // new revision info record.
00153                                           revision = line.substring(0, orIndex);
00154                                           buffer.append(line);
00155                                    }
00156                             }
00157                      }
00158                      reader.close();
00159                      
00160                      return new Blame(lines, info);
00161               } catch (Exception e) {
00162                      System.err.println("[error assigning blame for: " + bonsaiPath + "]"); 
00163                      e.printStackTrace(System.err);
00164               }
00165               return null;
00166        }
00167 }