On Thu 20 Dec 2007 at 08:02PM, Dan Price wrote:
> 
> My Holiday present to Opengrok is a wad which significantly improves
> support for Teamware repositories:
> 
>         - Opengrok now notices Codemgr_wsdata directories (i.e.
>           Teamware workspaces) during indexing.
> 
>         - SCCSGet has been rewritten to be a lot simpler, and much more
>           correct-- previous versions would emit corrupt files when
>           fetching non-"tip" versions of files.  Having looked at the
>           SCCS source code, I suspect that fixing the parser would
>           be non-trivial.
> 
>           SCCS is a complex format internally; previously opengrok was
>           coded to try to crack open the SCCS history file directly.  The
>           parsing algorithm for that was incorrect, and rather than
>           opting to fix it, I now just call out to the SCCS commands
>           directly.
> 
>         - Annotation support for files in Teamware repositories has
>           been added.
> 
>         - ExternalRepository has been refactored to accomodate
>           repositories which support file-history but not
>           directory-history.
> 
> Please take a look; this is working really nicely for me on my corpus
> of stuff.
> 
>         http://cr.opensolaris.org/~dp/og-teamware/

I've conducted a lot of testing on this code and I think it's hopefully
done.  I have updated the webrev.  The main changes this time are to
better support files which might be in a teamware repo, but not under
SCCS control.  This required some additional infrastructure.

Also, attached is the patch as an 'hg export' file.  Knut, Trond, if you
think it is ready, could you check it in?  If others want to help with
testing, I'd love for someone to make sure this works with Subversion.
I think it is OK on Mercurial, but more testing there also would not
hurt.

Thanks,

        -dp

-- 
Daniel Price - Solaris Kernel Engineering - dp at eng.sun.com - blogs.sun.com/dp
-------------- next part --------------
# HG changeset patch
# User Dan Price <dp at eng.sun.com>
# Date 1200018827 28800
# Node ID 604d16e382c0a95aa3136b02b22d4e314ec859bf
# Parent  634f5ed8552fac3dcc19c99dba2f475f09cdb97f
Add support for Teamware repositories

diff -r 634f5ed8552f -r 604d16e382c0 
src/org/opensolaris/opengrok/history/ExternalRepository.java
--- a/src/org/opensolaris/opengrok/history/ExternalRepository.java      Thu Jan 
10 23:17:24 2008 +0100
+++ b/src/org/opensolaris/opengrok/history/ExternalRepository.java      Thu Jan 
10 18:33:47 2008 -0800
@@ -39,6 +39,10 @@ public interface ExternalRepository {
      * @return a specialized parser for this kind of repository
      */
     Class<? extends HistoryParser> getHistoryParser();
+    
+    Class<? extends HistoryParser> getDirectoryHistoryParser();
+    
+    public boolean fileHasHistory(File file);
     
     /**
      * Get an input stream that I may use to read a speciffic version of a
diff -r 634f5ed8552f -r 604d16e382c0 
src/org/opensolaris/opengrok/history/HistoryCache.java
--- a/src/org/opensolaris/opengrok/history/HistoryCache.java    Thu Jan 10 
23:17:24 2008 +0100
+++ b/src/org/opensolaris/opengrok/history/HistoryCache.java    Thu Jan 10 
18:33:47 2008 -0800
@@ -81,7 +81,13 @@ class HistoryCache {
             time = System.currentTimeMillis();
             history = parser.parse(file, repository);
             time = System.currentTimeMillis() - time;
-        } catch (Exception e) {
+        } catch (UnsupportedOperationException e) {
+            // In this case, we've found a file for which the SCM has no 
history
+            // An example is a non-SCCS file somewhere in an SCCS-controlled
+            // workspace.
+            return null;
+        }
+        catch (Exception e) {
             System.err.println("Failed to parse " + file.getAbsolutePath());
             e.printStackTrace();
             throw e;
diff -r 634f5ed8552f -r 604d16e382c0 
src/org/opensolaris/opengrok/history/HistoryGuru.java
--- a/src/org/opensolaris/opengrok/history/HistoryGuru.java     Thu Jan 10 
23:17:24 2008 +0100
+++ b/src/org/opensolaris/opengrok/history/HistoryGuru.java     Thu Jan 10 
18:33:47 2008 -0800
@@ -127,7 +127,8 @@ public class HistoryGuru {
                 hpClass = RCSHistoryParser.class;
                 previousFile = SCM.RCS;
             } else {
-                if (SCCSHistoryParser.getSCCSFile(file).canRead()) {
+                File sccsfile = SCCSHistoryParser.getSCCSFile(file);
+                if (sccsfile != null && sccsfile.canRead()) {
                     hpClass = SCCSHistoryParser.class;
                     previousFile = SCM.SCCS;
                 }
@@ -145,35 +146,34 @@ public class HistoryGuru {
      * Get the <code>HistoryParser</code> to use for the specified file.
      */
     private Class<? extends HistoryParser> getHistoryParser(File file) {
-        Class<? extends HistoryParser> parser = null;
 
         switch (previousFile) {
         case EXTERNAL:
             ExternalRepository repos = getRepository(file.getParentFile());
-            if (repos != null) {
+            if (repos != null && repos.fileHasHistory(file)) {
+                Class<? extends HistoryParser> parser;
                 parser = repos.getHistoryParser();
+                if (parser != null)
+                    return parser;
             }
             break;
         case RCS:
             File rcsfile = RCSHistoryParser.getRCSFile(file);
             if (rcsfile != null && rcsfile.exists()) {
-                parser = RCSHistoryParser.class;
+                return RCSHistoryParser.class;
             }
             break;
         case SCCS:
-            if (SCCSHistoryParser.getSCCSFile(file).canRead()) {
-                parser = SCCSHistoryParser.class;
+            File sccsfile = SCCSHistoryParser.getSCCSFile(file);
+            if (sccsfile != null && sccsfile.canRead()) {
+                return SCCSHistoryParser.class;
             }
             break;
         }
 
-        if (parser == null) {
-            // I did not find a match for the specified system. try to guess..
-            parser = guessHistoryParser(file);
-        }
-
-        return parser;
-    }
+        // I did not find a match for the specified system. try to guess..
+        return guessHistoryParser(file);
+}
 
     /**
      * Annotate the specified revision of a file.
@@ -211,7 +211,10 @@ public class HistoryGuru {
         if (parser != null) {
             try {
                 ExternalRepository repos = getRepository(file.getParentFile());
-                return new HistoryReader(HistoryCache.get(file, parser, 
repos));
+                History history = HistoryCache.get(file, parser, repos);
+                if (history == null)
+                    return null;
+                return new HistoryReader(history);
             } catch (IOException ioe) {
                 throw ioe;
             } catch (Exception e) {
@@ -229,7 +232,7 @@ public class HistoryGuru {
         Class<? extends HistoryParser> parser = null;
         ExternalRepository repos = getRepository(file);
         if (repos != null) {
-            parser = repos.getHistoryParser();
+            parser = repos.getDirectoryHistoryParser();
         }
 
         if (parser == null) {
@@ -279,11 +282,11 @@ public class HistoryGuru {
             } else {
                 File history = SCCSHistoryParser.getSCCSFile(parent, basename);
                 if(history.canRead()) {
-                    in = new BufferedInputStream(new SCCSget(new 
FileInputStream(history), rev));
+                    in = new BufferedInputStream(new 
SCCSget(history.getCanonicalPath(), rev));
                     in.mark(32);
                     in.read();
                     in.reset();
-                    previousFile = SCM.RCS;
+                    previousFile = SCM.SCCS;
                 }
             }
         }
@@ -318,8 +321,8 @@ public class HistoryGuru {
                 
             case SCCS :
                 history = SCCSHistoryParser.getSCCSFile(parent, basename);
-                if(history.canRead()) {
-                    in = new BufferedInputStream(new SCCSget(new 
FileInputStream(history), rev));
+                if(history != null && history.canRead()) {
+                    in = new BufferedInputStream(new 
SCCSget(history.getCanonicalPath(), rev));
                     in.mark(32);
                     in.read();
                     in.reset();
@@ -375,7 +378,8 @@ public class HistoryGuru {
     public static void main(String[] args) {
         try{
             File f = new File(args[0]);
-            HistoryGuru.getInstance().addExternalRepositories(".");
+            File d = new File(".");
+            
HistoryGuru.getInstance().addExternalRepositories(d.getCanonicalPath());
             System.out.println("-----Reading comments as a reader");
             HistoryReader hr = HistoryGuru.getInstance().getHistoryReader(f);
             BufferedReader rr = new BufferedReader(hr);
@@ -475,7 +479,19 @@ public class HistoryGuru {
                         }
                     }
                     return;
-                } else if (name.equals("cvs") || name.equals("sccs") || 
name.equals("codemgr_wsdata")) {
+                } else if (name.equals("codemgr_wsdata")) {
+                    try {
+                        String s = 
files[ii].getParentFile().getCanonicalPath();
+                        System.out.println("Adding Teamware repository: <" + s 
+ ">");
+                        TeamwareRepository rep = new TeamwareRepository(s);
+                        addExternalRepository(rep, s, repos);
+                    } catch (IOException exp) {
+                        System.err.println("Failed to get canonical path for " 
+ files[ii].getName() + ": " + exp.getMessage());
+                        System.err.println("Repository will be ignored...");
+                        exp.printStackTrace(System.err);
+                    }
+                    return;
+                } else if (name.equals("cvs") || name.equals("sccs")) {
                     return;
                 }
             }
@@ -584,6 +600,13 @@ public class HistoryGuru {
     private ExternalRepository getRepository(File path) {
         Map<String, ExternalRepository> repos = 
RuntimeEnvironment.getInstance().getRepositories();
         
+        try {
+            path = path.getCanonicalFile();
+        } catch (IOException e) {
+            System.err.println("Failed to get canonical path for " + path);
+            e.printStackTrace();
+            return null;
+        }
         while (path != null) {
             try {
                 ExternalRepository r = repos.get(path.getCanonicalPath());
@@ -619,5 +642,5 @@ public class HistoryGuru {
         }
         return null;
     }
-    
+   
 }
diff -r 634f5ed8552f -r 604d16e382c0 
src/org/opensolaris/opengrok/history/MercurialRepository.java
--- a/src/org/opensolaris/opengrok/history/MercurialRepository.java     Thu Jan 
10 23:17:24 2008 +0100
+++ b/src/org/opensolaris/opengrok/history/MercurialRepository.java     Thu Jan 
10 18:33:47 2008 -0800
@@ -36,7 +36,6 @@ import java.util.Map;
 import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import org.opensolaris.opengrok.configuration.RuntimeEnvironment;
 
 /**
  * Access to a Mercurial repository.
@@ -149,6 +148,10 @@ public class MercurialRepository impleme
     }
     
     public Class<? extends HistoryParser> getHistoryParser() {
+        return MercurialHistoryParser.class;
+    }
+
+    public Class<? extends HistoryParser> getDirectoryHistoryParser() {
         return MercurialHistoryParser.class;
     }
 
@@ -296,5 +299,13 @@ public class MercurialRepository impleme
             }
         }
     }
+
+    public boolean fileHasHistory(File file) {
+        // Todo: is there a cheap test for whether mercurial has history
+        // available for a file?
+        // Otherwise, this is harmless, since mercurial's commands will just
+        // print nothing if there is no history.
+        return true;
+    }
 }
 
diff -r 634f5ed8552f -r 604d16e382c0 
src/org/opensolaris/opengrok/history/SCCSHistoryParser.java
--- a/src/org/opensolaris/opengrok/history/SCCSHistoryParser.java       Thu Jan 
10 23:17:24 2008 +0100
+++ b/src/org/opensolaris/opengrok/history/SCCSHistoryParser.java       Thu Jan 
10 18:33:47 2008 -0800
@@ -57,6 +57,11 @@ class SCCSHistoryParser implements Histo
     public History parse(File file, ExternalRepository repos)
         throws IOException
     {
+        File f = getSCCSFile(file);
+        if (f == null) {
+            return null;
+        }
+        
         in = new BufferedReader(new FileReader(getSCCSFile(file)));
         pass = sep = false;
         passRecord = true;
@@ -230,11 +235,17 @@ class SCCSHistoryParser implements Histo
         return(-1);
     }
 
-    protected static File getSCCSFile(File file) {
+    protected static File getSCCSFile(File file)
+    {
         return getSCCSFile(file.getParent(), file.getName());
     }
 
-    protected static File getSCCSFile(String parent, String name) {
-        return new File(parent + "/SCCS/s." + name);
+    protected static File getSCCSFile(String parent, String name)
+    {
+        File f = new File(parent + "/SCCS/s." + name);
+        if (!f.exists()) {
+            return null;
+        }
+        return f;
     }
 }
diff -r 634f5ed8552f -r 604d16e382c0 
src/org/opensolaris/opengrok/history/SCCSget.java
--- a/src/org/opensolaris/opengrok/history/SCCSget.java Thu Jan 10 23:17:24 
2008 +0100
+++ b/src/org/opensolaris/opengrok/history/SCCSget.java Thu Jan 10 18:33:47 
2008 -0800
@@ -31,314 +31,76 @@ import java.io.*;
 import java.io.*;
 import java.util.*;
 
-/**
- * Opens a s.file and reads out a required revision
- */
-public class SCCSget extends FilterInputStream {
-    boolean pass;
-    int field;
-    boolean sep;
-    String rev;
-    int version = 1;
-    boolean binary;
-    HashMap<String, Integer> deltaTable;
+
+public class SCCSget extends InputStream {
+    private BufferedInputStream stream;
     
-    private byte[] dBuf;       // buffer to put decoded bytes
-    private int dSize = 0;     // size of dBuf
-    private int dIndex = 0;    // index into dBuf
-    
-    /**
-     *
-     * @param in
-     * @param rev
-     */
-    public SCCSget(InputStream in, String rev) {
-        super(in);
-        pass = sep = binary = false;
-        field = 0;
-        deltaTable = new HashMap<String, Integer>();
-        this.rev = rev;
-        dBuf = new byte[45];
+    public SCCSget(String file) throws IOException, FileNotFoundException {
+        this(file, null);
     }
     
     /**
-     *
-     * @return if the s-dot-file contains ascii encoded binary files
+     * Pass null in version to get current revision
      */
-    public boolean isBinary() {
-        return binary;
+    public SCCSget(String file, String revision) throws IOException, 
FileNotFoundException {
+        String command = 
System.getProperty("org.opensolaris.opengrok.history.Teamware", "sccs");
+        
+        ArrayList<String> argv = new ArrayList<String>();
+        argv.add(command);
+        argv.add("get");
+        argv.add("-p");
+        if (revision != null) {
+            argv.add("-r" + revision);
+        }        
+        argv.add(file);
+        ProcessBuilder pb = new ProcessBuilder(argv);
+        Process process = pb.start();
+        StringBuilder strbuf = new StringBuilder();
+        String line;
+        
+        try {
+            BufferedReader in =
+                new BufferedReader(new InputStreamReader
+                                     (process.getInputStream()));
+            while ((line = in.readLine()) != null) {
+                strbuf.append(line);
+                strbuf.append("\n");
+            }
+        } finally {
+            // is this really the way to do it? seems a bit brutal...
+            try {
+                process.exitValue();
+            } catch (IllegalThreadStateException e) {
+                process.destroy();
+            }
+        }
+        stream = new BufferedInputStream(new 
ByteArrayInputStream(strbuf.toString().getBytes()));
     }
- /*
-    public String readRecord() throws java.io.IOException {
-        sep = true;
-        StringBuilder record = new StringBuilder(128);
-        int c;
-        while ((c = read()) > 01) {
-            record.append((char)c);
-        }
-        if (record.length() > 1) {
-            return record.toString();
-        } else {
-            return null;
+
+    @Override public void reset() throws IOException {
+        try {
+            stream.reset();
+        } catch (IOException e) {
+            e.printStackTrace();
+            throw e;
         }
     }
-  */
-    /**
-     *
-     * @throws java.io.IOException
-     */
-    public final int read() throws java.io.IOException {
-        int c, d, delta, d1;
-        int till = 0;
-        if(binary && dIndex < dSize) {
-            return dBuf[dIndex++] & 0xff;
+    
+    @Override public void close() throws IOException {
+        if (stream != null) {
+            stream.close();
         }
-        
-        while((c = in.read()) != -1) {
-            if(c == 01) {
-                d = in.read();
-                switch (d) {
-                    case 'I':
-                        delta = readEol();
-                        //System.out.println("I = " + delta);
-                        if (pass && delta > version) {
-                            //System.out.println("---- IGNORING --- ");
-                            till = delta;
-                            pass = false;
-                        }
-                        break;
-                    case 'D':
-                        delta = readEol();
-                        //System.out.println("D = " + delta);
-                        if (pass && delta <= version) {
-                            //System.out.println("---- IGNORING --- ");
-                            till = delta;
-                            pass = false;
-                        }
-                        break;
-                    case 'E':
-                        delta = readEol();
-                        //System.out.println("E = " + delta);
-                        if(!pass && delta == till) {
-                            pass = true;
-                            //System.out.println("---- starting --- ");
-                        }
-                        break;
-                    case 'd':
-                        readDelta();
-                        break;
-                    case 'f':
-                        in.read();
-                        d1 = in.read();
-                        switch (d1) {
-                            case 'e':
-                                if(readEol() == 1) {
-                                    binary = true;
-                                }
-                                break;
-                            default:
-                                readEol();
-                        }
-                        break;
-                    case 'T':
-                        //System.out.println(deltaTable);
-                        Integer delVersion;
-                        if ((delVersion =  deltaTable.get(rev)) != null) {
-                            version = delVersion.intValue();
-                        } else {
-                            throw new IOException("No such verson");
-                        }
-                        in.read();     // ignore the newline after <soh>T
-                        pass = true;
-                        break;
-                    default:
-                        pass = false;
-                }
-            } else {
-                if (pass) {
-                    if (binary) {
-                        //System.out.println("dIndex = " + dIndex + " dSize=" 
+ dSize);
-                        if (dIndex >= dSize && !uuDecode(c)) {
-                            return -1;
-                        }
-                        //System.out.println("XXX: returning [" + dIndex + "] 
= " + dBuf[dIndex]);
-                        return dBuf[dIndex++] & 0xff;
-                    } else {
-                        return(c);
-                    }
-                }
-            }
-        }
-        return(-1);
     }
     
-    private int readEol() throws java.io.IOException {
-        int c;
-        int val = 0;
-        do {
-            c = in.read();
-            if (c > 0x29 && c < 0x40) {
-                val = val*10 + c - 0x30;
-            }
-        } while( c != -1 && c != '\n');
-        return val;
+    @Override public void mark(int readlimit) {
+        stream.mark(readlimit);
     }
     
-    private void readDelta() throws java.io.IOException {
-        int c;
-        int val = 0;
-        StringBuilder rev = new StringBuilder(8);
-        c = in.read();
-        c = in.read();
-        if(c == 'D') {
-            in.read();
-            /* read revision */
-            while((c = in.read()) != ' ') {
-                if(c == '\n' || c == -1) {
-                    return;
-                }
-                rev.append((char)c);
-            }
-            //System.out.print("REv = "+ rev);
-            /* skip date time uid */
-            int skip = 3;
-            while(skip > 0) {
-                c = in.read();
-                if(c == '\n' || c == -1)
-                    return;
-                if(c == ' ')
-                    skip--;
-            }
-            
-            /* read delta */
-            do {
-                c = in.read();
-                if (c > 0x29 && c < 0x40) {
-                    val = val*10 + c - 0x30;
-                }
-                if(c == '\n' || c == -1)
-                    return;
-            } while(c!= ' ');
-            //System.out.println(" VAL = "+ val);
-        }
-        do {
-            c = in.read();
-        } while (c != -1 && c != '\n');
-        if (val != 0) {
-            deltaTable.put(rev.toString(), new Integer(val));
-        }
-        return;
+    @Override public int read(byte[] buffer, int pos, int len) throws 
IOException {
+        return stream.read(buffer, pos, len);
     }
     
-    public int read(byte b[], int off, int len) throws IOException {
-        if (b == null) {
-            throw new NullPointerException();
-        } else if ((off < 0) || (off > b.length) || (len < 0) ||
-                ((off + len) > b.length) || ((off + len) < 0)) {
-            throw new IndexOutOfBoundsException();
-        } else if (len == 0) {
-            return 0;
-        }
-        
-        int c = read();
-        if (c == -1) {
-            return -1;
-        }
-        b[off] = (byte)c;
-        
-        int i = 1;
-        try {
-            for (; i < len ; i++) {
-                c = read();
-                if (c == -1) {
-                    break;
-                }
-                if (b != null) {
-                    b[off + i] = (byte)c;
-                }
-            }
-        } catch (IOException ee) {
-        }
-        return i;
-    }
-    
-    private boolean uuDecode(int count) throws IOException {
-        if (count == -1 || count == '\n') {
-            return false;
-        }
-        count = (count - ' ') & 0x3f;
-        if (count == 0) {
-            return false;
-        }
-        if (count > 45) {
-            throw new IOException("UUdecode: format excpetion: More than 45 
encoded chars in a line");
-        }
-        byte a, b;
-        dSize = 0;
-        dIndex = 0;
-        int x, y;
-        
-        while (dSize < count) {
-            x = in.read();
-            y = in.read();
-            if(x == -1 || y == -1) {
-                return false;
-            }
-            if(x == '\n' || y == '\n') {
-                throw new IOException("UUdecode: Format Excpetion: Unexpected 
EOL!");
-            }
-            a = (byte)((x - ' ') & 0x3f);
-            b = (byte)((y - ' ') & 0x3f);
-            dBuf[dSize++] = (byte)(((a << 2) & 0xfc) | ((b >>> 4) & 3));
-            
-            if (dSize < count) {
-                a = b;
-                x = in.read();
-                if(x == -1) {
-                    return false;
-                }
-                if(x == '\n') {
-                    throw new IOException("UUdecode: Format Excpetion: 
Unexpected EOL!");
-                }
-                b = (byte)((x - ' ') & 0x3f);
-                dBuf[dSize++] = (byte)(((a << 4) & 0xf0) | ((b >>> 2) & 0xf));
-            }
-            
-            if (dSize < count) {
-                a = b;
-                x = in.read();
-                if(x == -1) {
-                    return false;
-                }
-                if(x == '\n') {
-                    throw new IOException("UUdecode: Format Excpetion: 
Unexpected EOL!");
-                }
-                b = (byte)((x - ' ') & 0x3f);
-                dBuf[dSize++] = (byte)(((a << 6) & 0xc0) | (b & 0x3f));
-            }
-        }
-        do {
-            x = in.read();
-        } while (x != '\n' && x != -1);
-        return true;
-    }
-    
-    /**
-     *
-     * @param args
-     */
-    public static void main(String[] args) {
-        try {
-            SCCSget get = new SCCSget(new BufferedInputStream(new 
FileInputStream(args[0])),
-                    args[1]);
-//            OutputStreamWriter out = new OutputStreamWriter(System.out);
-            int c;
-            while ((c = get.read()) != -1) {
-                System.out.write(c);
-            }
-            // out.close();
-        } catch (Exception e) {
-            System.err.println(e+"\n USAGE: s.file rev");
-        }
+    public int read() throws IOException {
+        throw new IOException("use a BufferedInputStream. just read() is not 
supported!");
     }
 }
diff -r 634f5ed8552f -r 604d16e382c0 
src/org/opensolaris/opengrok/history/SubversionRepository.java
--- a/src/org/opensolaris/opengrok/history/SubversionRepository.java    Thu Jan 
10 23:17:24 2008 +0100
+++ b/src/org/opensolaris/opengrok/history/SubversionRepository.java    Thu Jan 
10 18:33:47 2008 -0800
@@ -135,6 +135,10 @@ public class SubversionRepository implem
         return SubversionHistoryParser.class;
     }
 
+    public Class<? extends HistoryParser> getDirectoryHistoryParser() {
+        return SubversionHistoryParser.class;
+    }
+    
     /**
      * Get the name of the root directory for this repository
      * @return the name of the directory containing the .svn subdirectory
@@ -238,6 +242,13 @@ public class SubversionRepository implem
     public boolean isCacheable() {
         return true;
     }
+    
+    public boolean fileHasHistory(File file) {
+        // TODO: Research how to cheaply test if a file in a given
+        // SVN repo has history.  If there is a cheap test, then this
+        // code can be refined, boosting performance.
+        return true;
+    }
 
     public void update() throws Exception {
         Process process = null;
diff -r 634f5ed8552f -r 604d16e382c0 
src/org/opensolaris/opengrok/history/TeamwareRepository.java
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/opensolaris/opengrok/history/TeamwareRepository.java      Thu Jan 
10 18:33:47 2008 -0800
@@ -0,0 +1,272 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * See LICENSE.txt included in this distribution for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at LICENSE.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+package org.opensolaris.opengrok.history;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ *
+ *
+ */
+public class TeamwareRepository implements ExternalRepository {
+    private File directory;
+    private String directoryName;
+    private String command;
+    private boolean verbose;
+    private Map<String, String> authors_cache;
+    
+    /**
+     * Creates a new instance of MercurialRepository
+     */
+    public TeamwareRepository() { }
+    
+    /**
+     * Creates a new instance of MercurialRepository
+     * @param directory The directory containing the .hg-subdirectory
+     */
+    public TeamwareRepository(String directory) {
+        this.directory = new File(directory);
+        directoryName = this.directory.getAbsolutePath();
+        command = 
System.getProperty("org.opensolaris.opengrok.history.Teamware", "sccs");
+    }
+    
+    /**
+     * Set the name of the SCCS command to use
+     * @param command the name of the command (sccs)
+     */
+    public void setCommand(String command) {
+        this.command = command;
+    }
+
+    /**
+     * Get the name of the SCCS command that should be used
+     * @return the name of the sccs command in use
+     */
+    public String getCommand() {
+        return command;
+    }
+    
+    /**
+     * Use verbose log messages, or just the summary
+     * @return true if verbose log messages are used for this repository
+     */
+    public boolean isVerbose() {
+        return verbose;
+    }
+        
+    /**
+     * Specify if verbose log messages or just the summary should be used
+     * @param verbose set to true if verbose messages should be used
+     */
+    public void setVerbose(boolean verbose) {
+        this.verbose = verbose;
+    }
+    
+    public InputStream getHistoryGet(String parent, String basename, String 
rev) {
+        try {
+            File history = SCCSHistoryParser.getSCCSFile(parent, basename);
+            return new BufferedInputStream(new 
SCCSget(history.getCanonicalPath(), rev));
+        } catch (FileNotFoundException ex) {
+            return null;
+        } catch (IOException ex) {
+            return null;
+        }
+    }
+    
+     /** Pattern used to extract revision from sccs get */
+    private final static Pattern AUTHOR_PATTERN =
+        Pattern.compile("^([\\d.]+)\\s+(\\S+)");
+    
+    private void getAuthors(File file) throws IOException {
+        //System.out.println("Alloc Authors cache");
+        authors_cache = new HashMap<String, String>();
+
+        ArrayList<String> argv = new ArrayList<String>();
+        argv.add(command);
+        argv.add("prs");
+        argv.add("-e");
+        argv.add("-d");
+        argv.add(":I: :P:");
+        argv.add(file.getCanonicalPath());
+
+        ProcessBuilder pb = new ProcessBuilder(argv);
+        pb.directory(file.getCanonicalFile().getParentFile());
+        Process process = pb.start();
+        
+        try {
+            BufferedReader in =
+                new BufferedReader(new InputStreamReader
+                                     (process.getInputStream()));
+            String line;
+            int lineno = 0;
+            while ((line = in.readLine()) != null) {
+                ++lineno;
+                Matcher matcher = AUTHOR_PATTERN.matcher(line);
+                if (matcher.find()) {
+                    String rev = matcher.group(1);
+                    String auth = matcher.group(2);
+                    authors_cache.put(rev, auth);
+                } else {
+                    System.err.println("Error: did not find annotation in line 
" + lineno);
+                    System.err.println("[" + line + "]");
+                }
+            }
+        } finally {
+            // is this really the way to do it? seems a bit brutal...
+            try {
+                process.exitValue();
+            } catch (IllegalThreadStateException e) {
+                process.destroy();
+            }
+        }
+    }
+    
+    public Class<? extends HistoryParser> getHistoryParser() {
+        return SCCSHistoryParser.class;
+    }
+
+    
+    public Class<? extends HistoryParser> getDirectoryHistoryParser() {
+        // No directory history with Teamware
+        return null;
+    }
+
+    /** Pattern used to extract revision from sccs get */
+    private final static Pattern ANNOTATION_PATTERN =
+        Pattern.compile("^([\\d.]+)\\s+");
+
+    /**
+     * Annotate the specified file/revision.
+     *
+     * @param file file to annotate
+     * @param revision revision to annotate
+     * @return file annotation
+     */
+    public Annotation annotate(File file, String revision) throws Exception {
+        
+        //System.out.println("annotating " + file.getCanonicalPath());
+        getAuthors(file);
+        
+        ArrayList<String> argv = new ArrayList<String>();
+        argv.add(command);
+        argv.add("get");
+        argv.add("-m");
+        argv.add("-p");
+        if (revision != null) {
+            argv.add("-r" + revision);
+        }
+        argv.add(file.getCanonicalPath());
+        ProcessBuilder pb = new ProcessBuilder(argv);
+        pb.directory(file.getCanonicalFile().getParentFile());
+        Process process = pb.start();
+        try {
+            BufferedReader in =
+                new BufferedReader(new InputStreamReader
+                                     (process.getInputStream()));
+            Annotation a = new Annotation(file.getName());
+            String line;
+            int lineno = 0;
+            while ((line = in.readLine()) != null) {
+                ++lineno;
+                Matcher matcher = ANNOTATION_PATTERN.matcher(line);
+                if (matcher.find()) {
+                    String rev = matcher.group(1);
+                    String author = authors_cache.get(rev);
+                    if (author == null)
+                        author = "unknown";
+                    
+                    a.addLine(rev, author, true);
+                } else {
+                    System.err.println("Error: did not find annotation in line 
" + lineno);
+                    System.err.println("[" + line + "]");
+                }
+            }
+            return a;
+        } finally {
+            // is this really the way to do it? seems a bit brutal...
+            try {
+                process.exitValue();
+            } catch (IllegalThreadStateException e) {
+                process.destroy();
+            }
+        }
+    }
+
+    /**
+     * Get the name of the root directory for this repository
+     * @return the name of the directory containing the .hg subdirectory
+     */
+    public String getDirectoryName() {
+        return directoryName;
+    }
+    
+    /**
+     * Specify the name of the root directory for this repository
+     * @param directoryName the new name of the directory containing the .hg 
+     *        subdirectory
+     */
+    public void setDirectoryName(String directoryName) {
+        this.directoryName = directoryName;
+        this.directory = new File(this.directoryName);
+    }
+    
+    public void createCache() throws IOException, ParseException {
+        // TODO later
+    }
+
+    public boolean supportsAnnotation() {
+        return true;
+    }
+
+    public boolean isCacheable() {
+        return false;
+    }
+
+    public void update() throws Exception {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public boolean fileHasHistory(File file) {
+        String parent = file.getParent();
+        String name = file.getName();
+        File f = new File(parent + "/SCCS/s." + name);
+        if (f.exists()) {
+            return true;
+        }
+        return false;
+    }
+}
+
diff -r 634f5ed8552f -r 604d16e382c0 
src/org/opensolaris/opengrok/index/IndexDatabase.java
--- a/src/org/opensolaris/opengrok/index/IndexDatabase.java     Thu Jan 10 
23:17:24 2008 +0100
+++ b/src/org/opensolaris/opengrok/index/IndexDatabase.java     Thu Jan 10 
18:33:47 2008 -0800
@@ -289,7 +289,13 @@ public class IndexDatabase {
      * @throws java.io.IOException if an error occurs
      */
     private void addFile(File file, String path) throws IOException {
-        InputStream in = new BufferedInputStream(new FileInputStream(file));
+        InputStream in;
+        try {
+            in = new BufferedInputStream(new FileInputStream(file));
+        } catch (IOException ex) {
+            System.err.println("Warning: " + ex.getMessage());
+            return;
+        }
         FileAnalyzer fa = AnalyzerGuru.getAnalyzer(in, path);
 
         for (IndexChangedListener listener : listeners) {

Reply via email to