This is VCI, the generic Version Control Interface. The goal of VCI is to create a common API that can interface with all version control systems (which are sometimes also called Software Configuration Management or "SCM" systems).

The general interface of VCI is described in the various VCI::Abstract modules, and those contain the documentation you should read in order to find out how VCI works.

"Drivers" for different VCSes are in modules whose names start with VCI::VCS. For example, VCI::VCS::Cvs is the "CVS support" for VCI. You only have to read VCI::VCS::Cvs or the manual of any other driver if you want to know:

The general interface of VCI classes is described in the VCI::Abstract modules, but the specific implementations for particular VCSes are in the VCI::VCS namespace.

For example, the methods that you use on a File in your version-control system are described in VCI::Abstract::File, but the actual specific implementation for CVS is in VCI::Cvs::File. VCI::Cvs::Filemust implement all of the methods described in VCI::Abstract::File, but it also may implement extension methods whose names start with x_.

If you are going to use isa on objects to check their type, you should check that they are the abstract type, not the specific type. For example, to find out if an object is a File, you would do:

As long as this number is 0, major breaking changes may occur to the API all the time. When this becomes 1, the API is stable. For numbers greater than 1, it means we made a major breaking change to the API.

For example, VCI 2.0.1 would have breaking changes for the user or for the drivers, compared to VCI 1.0.1. But VCI 0.1.1 and 0.2.1 could contain breaking changes between them, also, because the first number is still 0.

VCI has various features, but the drivers may not implement all of these features. So, when we add new features that drivers must implement, the API number gets incremented.

For example, VCI 0.0.1 doesn't have support for authenticating to repositories, but VCI 0.2.1 might support it.

Drivers will say which VCI API they support. Using a driver that doesn't support the current VCI API will throw a warning if "debug" mode is on. Using a driver that supports an API later than the current VCI will throw an error.

Note that you cannot currently connect to repositories that require authentication, as VCI has no way of dealing with usernames or passwords. So you must connect to repositories that don't require authentication, or to which you have already authenticated. Future versions of VCI will support authentication.

This is a string representing the repository you want to connect to, in the exact same format that you'd pass to the command-line interface to your VCS. For example, for CVS this would be the contents of CVSROOT.

The documentation of individual drivers will explain what the format required for this field is.

Taint Mode: VCI will throw an error if this is tainted, because drivers use this string to do various operations (such as filesystem operations) that could be unsafe with untrusted data. If VCI didn't throw the error, you'd instead get some weird error from some internal part of VCI or one of the modules it uses, so it's better to just throw it right here.

Some drivers have requirements beyond just Perl modules, in order to work. Calling this method will tell you if those requirements are installed. You would call this method like:

use VCI::VCS::Cvs;
my @need = VCI::VCS::Cvs->missing_requirements;

Returns an array (not an arrayref) of strings representing items that still need to be installed in order for this driver to function. If the array is empty, then all non-Perl requirements for this driver are already installed and available.

These represent information about a particular version-control system. You can call these on a class, like VCI::VCS::Cvs->revisions_are_universal, or if you have a VCI::Abstract::Repository object, you can call these methods using the vci accessor, like: $repository->vci->revisions_are_universal.

A boolean. If true, then the "revision" accessor on a VCI::Abstract::Commit for this VCS is globally unique within an entire Repository, not just for this Project. (For example, Subversion's commit ids are globally unique within a repository.)

If false, then different Projects could have overlapping revision identifiers.

A boolean. If true, then the "revision" accessor on a VCI::Abstract::Commit returns a value that will be universally unique across all repositories in the world. For example, Git, Mercurial, and Bazaar have universally unique revision identifiers--no two revisions in existence are likely to have duplicate revision ids unless they are actually the same revision.

VCI strives to perform well. It will never perform faster than the VCS being used, however. Also, on very large projects (tens of thousands of files or tens of thousands of commits) some operations may be slow (such as asking for the History of an entire Project). However, for most uses and for the majority of projects, VCI should be fast enough.

Using local repositories is always faster than using remote repositories, usually by orders of magnitude.

VCI uses Moose extensively, so installing the latest version of Moose often helps improve the performance of VCI.

If the performance of VCI is too slow for your project, please let the author know using one of the mechanisms described in "SUPPORT". Without knowing exactly what sort of things are slow in real-world use, it's impossible to know what to optimize.

VCI uses Moose, so all constructors for all objects are called new (although for VCI itself you'll want to use "connect"), and they all take named parameters as a hash (not a hashref). Generally users don't call constructors--we only call constructors internally.

If the POD of the VCI::Abstract modules says something, that is an API for VCI. Unless the POD specifically says you can change the behavior of a method, you must not deviate from how the POD says the methods and accessors work.

You may add new required attributes to the constructors of various modules, but you must not add required attributes to methods other than what is already specified in the POD for that method.

VCI provides a base set of functions that are common to all Version-Control Systems, but if your VCS can do special things, feel free to add extension methods.

So that your methods don't conflict with VCI methods, their names should start with x_ (or _x_ for private methods). VCI won't enforce that, but if you don't do it, your module could seriously break in the future if VCI implements a method with the same name as yours.

VCI promises not to have any abstract methods or accesors that start with x_ or _x_.

This means that drivers (and VCI) should do exactly what the user asks, without any surprises or side-effects, and should conform fully to all required elements of the API.

If you have doubts about what is "correct", ask yourself the question, "What would be most logical for a web application that views and interacts with a repository?" That is the function that VCI was originally designed for.

In general, VCI strives to be efficient in terms of speed. Working with a version-control system can often be a slow experience, and we don't want to make that any worse than it already is.

This means that individual methods should do the least work possible to return the information that the user needs, and store it internally for later use.

For example, a file in a version control system has a first revision . If there's a fast way to just get the first revision, you should do that.

But if we've already read the whole history of a file, that has information about the first revision in it, so we should just be able to reference the history we already retrieved, instead of asking the version-control system for the first revision all over again.

In general, you shouldn't override "connect". Also, using before on "connect" probably also isn't a good idea. You could use after, but it mostly just makes sense to implement "_build_repository" and leave it at that.

If you do override connect, you must call thisconnect at some point in your connect.