CVS -- No File System There!

As a CVS client, we have no way to browse the repository directly.

The best we can do is execute a Checkout command and parse the data returned.

public class CvsResourceServer extends ResourceServerBasics {

    private void updateCvsData() throws IOException {
        openConversation();
        if (root != null) {
            sendUnchanged((CvsCategory)root);
        }
        outstream.println("Directory .");
        outstream.println(cvsRepositoryPath);
        outstream.println("Argument -A");
        outstream.println("Argument " + rootPath);
        outstream.println("co");
        while (true) {
            String line = instream.readln();
            if (line.startsWith("Clear-sticky ")) {
                . . .
            }
            if (line.startsWith("Created ") || line.startsWith("Updated ")) {
                . . .
            }
            if (line.startsWith("Removed ")) {
                . . .
            }
            if (line.startsWith("E ") || line.startsWith("M ")) {
                . . .
            }
            break;
        }
        closeComm();
    }
}
Ordinary CVS clients save the repository data in all the extra "CVS" directories littering your source code directories.
     Entries      Repository      Root
The CvsResourceServer saves this data in the Categories and Resources themselves.
CvsResourceServer
cvsRoot : String
root : Category
getParentCategory(Category) : Category
getResources(Category) : Resource[]
getSubCategories(Category) : Category[]
    
CvsCategory
repository : String
parentCategory : CvsCategory
subCategories : CvsCategory[]
resources : CvsResource[]
getRepository() : String
getResources() : Resource[]
getParentCategory() : Category
getSubCategories() : Category[]
    
CvsResource
entry : String
parentCategory : CvsCategory
getEntry() : String
getRepository() : String
getCategory() : CvsCategory
The Cvs Categories and Resources link together in a tree structure.

To avoid having to do a Checkout of all the files in a repository every time Kahuna starts up, we serialize this data structure on shutdown and read it back on startup.

public class CvsResourceServer extends ResourceServerBasics {

    private void serializeCvsData() throws IOException {
        FileOutputStream fos = new FileOutputStream("cvsdata.serialized");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(root);
        oos.flush();
        oos.close();
    }

    private void deserializeCvsData() {
        try {
            FileInputStream fis = new FileInputStream("cvsdata.serialized");
            ObjectInputStream ois = new ObjectInputStream(fis);
            root = (CvsCategory)ois.readObject();
            ois.close();
            ((CvsCategory)root).setServer(this);
        } catch (Exception e) {
            root = null;
        }
    }
}
Then, as part of the Checkout command, we tell the CVS server that these files do not need to be updated.
public class CvsResourceServer extends ResourceServerBasics {

    private void sendUnchanged(CvsCategory category) throws IOException {
        String repository = category.getRepository();
        String directory = getDirectory(repository);
        outstream.println("Directory ." + directory);
        outstream.println(repository);
        Resource[] resources = category.getResources();
        for (int i = 0; i < resources.length; i++) {
            CvsResource resource = (CvsResource)resources[i];
            outstream.println("Entry " + resource.getEntry());
            outstream.println("Unchanged " + resource.getName());
        }
        Category[] categories = category.getSubCategories();
        for (int i = 0; i < categories.length; i++) {
            CvsCategory subCategory = (CvsCategory)categories[i];
            sendUnchanged(subCategory);
        }
    }
}