Source code for jasy.vcs.Git

#
# Jasy - Web Tooling Framework
# Copyright 2010-2012 Zynga Inc.
#

import os.path
import re
import urllib.parse
import shutil

from jasy.core.Util import executeCommand
import jasy.core.Console as Console


__versionNumber = re.compile(r"^v?([0-9\.]+)(-?(a|b|rc|alpha|beta)([0-9]+)?)?\+?$")

__gitAccountUrl = re.compile("([a-zA-Z0-9-_]+)@([a-zA-Z0-9-_\.]+):([a-zA-Z0-9/_-]+\.git)")
__gitHash = re.compile(r"^[a-f0-9]{40}$")
__gitSchemes = ('git', 'git+http', 'git+https', 'git+ssh', 'git+git', 'git+file')


[docs]def update(url, version, path, update=True, submodules=True): """Clones the given repository URL (optionally with overriding/update features)""" # Prepend git+ so that user knows that we identified the URL as git repository if not url.startswith("git+"): url = "git+%s" % url old = os.getcwd() if os.path.exists(path) and os.path.exists(os.path.join(path, ".git")): if not os.path.exists(os.path.join(path, ".git", "HEAD")): Console.error("Invalid git clone. Cleaning up...") shutil.rmtree(path) else: os.chdir(path) revision = executeCommand(["git", "rev-parse", "HEAD"], "Could not detect current revision") if update and (version == "master" or "refs/heads/" in version): if update: Console.info("Updating %s", Console.colorize("%s @ " % url, "bold") + Console.colorize(version, "magenta")) Console.indent() try: executeCommand(["git", "fetch", "-q", "--depth", "1", "origin", version], "Could not fetch updated revision!") executeCommand(["git", "reset", "-q", "--hard", "FETCH_HEAD"], "Could not update checkout!") newRevision = executeCommand(["git", "rev-parse", "HEAD"], "Could not detect current revision") if revision != newRevision: Console.info("Updated from %s to %s", revision[:10], newRevision[:10]) revision = newRevision if submodules and os.path.exists(".gitmodules"): Console.info("Updating sub modules (this might take some time)...") executeCommand("git submodule update --recursive", "Could not initialize sub modules") except Exception: Console.error("Error during git transaction! Could not update clone.") Console.error("Please verify that the host is reachable or disable automatic branch updates.") Console.outdent() os.chdir(old) return except KeyboardInterrupt: print() Console.error("Git transaction was aborted by user!") Console.outdent() os.chdir(old) return Console.outdent() else: Console.debug("Updates disabled") else: Console.debug("Using existing clone") os.chdir(old) return revision Console.info("Cloning %s", Console.colorize("%s @ " % url, "bold") + Console.colorize(version, "magenta")) Console.indent() os.makedirs(path) os.chdir(path) try: # cut of "git+" prefix remoteurl = url[4:] executeCommand(["git", "init", "."], "Could not initialize GIT repository!") executeCommand(["git", "remote", "add", "origin", remoteurl], "Could not register remote repository!") executeCommand(["git", "fetch", "-q", "--depth", "1", "origin", version], "Could not fetch revision!") executeCommand(["git", "reset", "-q", "--hard", "FETCH_HEAD"], "Could not update checkout!") revision = executeCommand(["git", "rev-parse", "HEAD"], "Could not detect current revision") if submodules and os.path.exists(".gitmodules"): Console.info("Updating sub modules (this might take some time)...") executeCommand("git submodule update --init --recursive", "Could not initialize sub modules") except Exception: Console.error("Error during git transaction! Intitial clone required for continuing!") Console.error("Please verify that the host is reachable.") Console.error("Cleaning up...") os.chdir(old) shutil.rmtree(path) Console.outdent() return except KeyboardInterrupt: print() Console.error("Git transaction was aborted by user!") Console.error("Cleaning up...") os.chdir(old) shutil.rmtree(path) Console.outdent() return os.chdir(old) Console.outdent() return revision
[docs]def getBranch(path=None): """Returns the name of the git branch.""" return executeCommand("git rev-parse --abbrev-ref HEAD", "Could not figure out git branch. Is there a valid Git repository?", path=path)
[docs]def getRevision(path=None): """Returns the last revision/hash of the git repository.""" return executeCommand("git rev-parse HEAD", "Could not figure out git revision. Is there a valid Git repository?", path=path)
[docs]def getShortRevision(path=None): """Returns the last shortened revision/hash of the git repository.""" return executeCommand("git rev-parse --short HEAD", "Could not figure out git revision. Is there a valid Git repository?", path=path)
[docs]def isUrl(url): """Figures out whether the given string is a valid Git repository URL.""" parsed = urllib.parse.urlparse(url) if not parsed.params and not parsed.query and not parsed.fragment: if parsed.scheme in __gitSchemes: return True elif parsed.scheme == "https" and parsed.path.endswith(".git"): return True elif not parsed.scheme and parsed.path == url and __gitAccountUrl.match(url) is not None: return True return False
[docs]def expandVersion(version=None): if version is None: version = "master" version = str(version) if version.startswith("refs/"): pass elif re.compile(r"^[a-f0-9]{40}$").match(version): # See also: http://git.661346.n2.nabble.com/Fetch-by-SHA-missing-td5604552.html raise Exception("Can't fetch non tags/branches: %s@%s!" % (url, version)) elif __versionNumber.match(version) is not None: version = "refs/tags/" + version else: version = "refs/heads/" + version return version
[docs]def cleanRepository(): """Cleans git repository from untracked files.""" return executeCommand(["git", "clean", "-d", "-f"], "Could not clean GIT repository!")
[docs]def distcleanRepository(): """ Cleans git repository from untracked files. Ignores the files listed in ".gitignore". """ return executeCommand(["git", "clean", "-d", "-f", "-x"], "Could not distclean GIT repository!")