--- versioncontrol.py.orig 2007-07-20 22:32:30.000000000 +0200 +++ versioncontrol.py 2007-07-20 22:39:34.000000000 +0200 @@ -318,9 +318,87 @@ raise IOError("darcs error running '%s': %s" % (command, error)) return output +class GIT(GenericVersionControlSystem): + """Class to manage items under revision control of git.""" + + # This assumes that the whole PO directory is stored in git so we need to + # reach the .git dir from po/project/language. That results in this + # relative path + MARKER_DIR = ".git" + + def __init__(self, location): + self.location = None + try: + # this works only, if the po file is in the root of the repository + GenericVersionControlSystem.__init__(self, location) + self.gitdir = os.path.join(os.path.dirname(os.path.abspath(location)), + self.MARKER_DIR) + self.location = os.path.abspath(location) + # we finished successfully + except IOError, err_msg: + # the following code scans all directories above the po file for the + # common '.git' directory + # first: resolve possible symlinks + current_dir = os.path.realpath(os.path.dirname(location)) + # avoid any dead loops (could this happen?) + max_depth = 64 + while not os.path.isdir(os.path.join(current_dir, self.MARKER_DIR)): + if os.path.dirname(current_dir) == current_dir: + # we reached the root directory - stop + break + if max_depth <= 0: + # some kind of dead loop or a _very_ deep directory structure + break + # go to the next higher level + current_dir = os.path.dirname(current_dir) + else: + # we found the MARKER_DIR + self.gitdir = current_dir + # retrieve the relative path of the po file based on self.gitdir + realpath_pofile = os.path.realpath(location) + basedir = self.gitdir + os.path.sep + if realpath_pofile.startswith(basedir): + # remove the base directory (including the trailing slash) + self.location = realpath_pofile.replace(basedir, "", 1) + # successfully finished + else: + # this should never happen + raise IOError("Git: unexpected path names: '%s' and '%s'" \ + % (self.gitdir, basedir)) + if self.location is None: + # we did not find a '.git' directory + raise IOError(err_msg) + + def update(self, revision=None): + """Does a clean update of the given path""" + command = "git checkout %s ; git pull" % shellescape(self.location) + output, error = pipe(command) + if error: + raise IOError("git error running '%s': %s" % (command, error)) + return output + + def commit(self, message=None): + """Commits the file and supplies the given commit message if present""" + if message is None: + message = "" + command = "git add %s; git commit -m '%s'; git push 2>/dev/null" \ + % (shellescape(self.location), message) + output, error = pipe(command) + if error: + raise IOError("Error running git command '%s': %s" % (command, error)) + return output + + def getcleanfile(self, revision=None): + """Get a clean version of a file from the git repository""" + command = "git cat-file blob $(git ls-tree HEAD %s|sed 's/.* \([a-f0-9]\{40\}\)\t.*/\1/')" \ + % shellescape(self.location) + output, error = pipe(command) + if error: + raise IOError("git error running '%s': %s" % (command, error)) + return output # which versioning systems are supported by default? -DEFAULT_VERSIONING_SYSTEMS = [CVS, SVN, DARCS] +DEFAULT_VERSIONING_SYSTEMS = [CVS, SVN, DARCS, GIT] def get_versioned_object( location,