Manage VCS pkgs (repos) in varying version control systems with ease through common interfaces.
Currently this has limited support for "get" (clone equivalent), "update" (various forms of fetching/merging/updating from a remote repo to the local instance) as well as some basic "reading" capability which can read version info from a local workspace or a given version (or set the current version to something else for reading... so perhaps a bit of a misnomer at the moment).
Git, SVN, Bazaar (Bzr), and Mercurial (Hg) are currently supported. They each
have their own type (e.g., GitReader
) that follow a simple naming pattern. Each
type implements the Reader
interface and has a constructor (e.g., NewGitReader
).
The constructors have the same signature as NewReader
.
The package golang.org/x/tools/go/vcs
provides some valuable functionality
for working with packages in repositories in varying source control management
systems. Beyond that other packages such as the 'nut' VCS tool vcs package and
the github.com/Masterminds/vcs ('glide' tool) packages all provided further
insights and capabilities. This is a fork of the Masterminds vcs pkg (thanks
much to all folks above and especially the Masterminds folks) but it has
diverged heavily and moves in different direction at this point.
The thought here is that most SCM/VCS tools seem to need specific operations such as update or clone (get) or diff or possibly reading data that already exists in the repo. Most o these also need to do things like check basic existence and describe where the repo is and what kind of op you want to perform (a description). The idea here is to set up interfaces for a Describer and to make an Updater be a describer but, beyond that, be primarily focused on being an updater (with some basic ability to check for existence and such). Aside: would use an Existence but how Go deals with multiple interfaces gets a little tricky when there is overlap (ie: if an Existence is a Describer and an Updater is a Describer then it's not possible to add Existence to Updater even if the signatures of the describe methods are exactly matching (which, of course, they are). Due to this you will see things like the routine Exists() defined in the Updater interface (vs sucking it in via the Existence interface).
With that in mind you'll see that one would instantiate the needed op by only using the minimal data needed for that operation. I find this to be useful when interacting with the SCM... and it keeps the interface to a bare minimum for whatever SCM op one might need to perform.
Currently only the git backend is Goroutine friendly (get/clone, upd/fetch/pull, revision reading, etc) and only the git backend implements the more extensive capabilities around mirror clones (or not) and mirror updates (or not) as well as specific fetch/delete ref targets working in both regular and mirror/bare clones. This is an early version with this target... after refining the git solution the next SCM targeted for "concurrent friendly" is Hg.
Haven't fleshed this README out as the API has been in flux. The test files should give a general idea for use, eg: git_test.go for example. Here's a quick example:
import (
"io/ioutil"
"os"
"github.com/dvln/vcs"
)
...
// ... note: we're updating a test repo here so that's what the tempDir points to ...
tempDir, err := ioutil.TempDir("", "vcs-test")
if err != nil {
//... error out as needed
}
sep := string(os.PathSeparator)
mirror := true
// Prep for a clone op, do not mirror the repo just a normal clone
getter, err := NewGetter("https://github.com/dvln/git-test-repo", tempDir+sep+"VCSTestRepo", !mirror)
if err != nil {
//... error out as needed
}
// Do an initial clone, all raw SCM cmd/output run is in the "results" (a "Resulter" interface)
results, err := getter.Get()
if err != nil {
t.Fatalf("Unable to clone Git repo using VCS reader Get(). Err was %s, results:\n%s", err, results)
}
// Perform an update operation, not mirroring (just a regular clone), don't use
// rebase (one can indcate don't use rebase, use rebase or use the users default)
updater, err := NewUpdater("", "origin", tempDir+sep+"VCSTestRepo", !mirror, RebaseUser, nil)
if err != nil {
//... error out as needed
}
results, err = updater.Update()
if err != nil {
//... error out as needed
}
That's about it. You created an updater (gitUpdater) and then you ran update on it. The various options allow one to do a mirror update ("git remote update --prune") as well as add specific git refs (eg: "refs/heads/master") via the last option. How those refs are fetched depends upon mirror mode or not (if mirroring fetch them to the same name, if not mirroring fetch heads to refs/remotes/origin/master for example). As always the code is the master source for info.
This is very early pre-release work that is not in use or ready for regular use (currently: v0.3.0). Feel free to fork and give suggestions of course but know it will be undergoing dramatic change throughout 2016 (at least). If you use it make sure you vendor it locally as the API may change.