summaryrefslogtreecommitdiffstats
path: root/nbb/nbblib/vcs.py
diff options
context:
space:
mode:
Diffstat (limited to 'nbb/nbblib/vcs.py')
-rw-r--r--nbb/nbblib/vcs.py216
1 files changed, 216 insertions, 0 deletions
diff --git a/nbb/nbblib/vcs.py b/nbb/nbblib/vcs.py
new file mode 100644
index 0000000..164077b
--- /dev/null
+++ b/nbb/nbblib/vcs.py
@@ -0,0 +1,216 @@
+import os
+import urlparse
+
+
+from nbblib.package import *
+from nbblib.plugins import *
+from nbblib.progutils import *
+
+
+class AbstractConfig(object):
+ """Return static config until we implement real config reading"""
+
+ def __init__(self, srcdir, nick):
+ super(AbstractConfig, self).__init__()
+ self._srcdir = srcdir
+ self._nick = nick
+
+ def get_srcdir(self):
+ return os.path.join(self._srcdir)
+ srcdir = property(get_srcdir)
+
+ def get_builddir(self):
+ return os.path.join(self._srcdir, "_build", self._nick)
+ builddir = property(get_builddir)
+
+ def get_installdir(self):
+ return os.path.join(self._srcdir, "_install", self._nick)
+ installdir = property(get_installdir)
+
+
+########################################################################
+# VCS Source Tree plugin system
+########################################################################
+
+class NotAVCSourceTree(Exception):
+ pass
+
+
+class AmbigousVCSource(Exception):
+ def __init__(self, srcdir, matches):
+ super(AmbigousVCSource, self).__init__()
+ self.srcdir = srcdir
+ self.matches = matches
+ def __str__(self):
+ fmt = " %-9s %-15s %s"
+ def strmatch(m):
+ return fmt % (m.name, m.branch_name(), m.tree_root())
+ alist = [fmt % ('VCS Type', 'Branch Name', 'Source tree root')] + map(strmatch, self.matches)
+ return ("More than one source tree VCS type detected for '%s':\n#%s"
+ % (self.srcdir, '\n '.join(alist)))
+
+
+class VCSourceTree(object):
+ """
+ Mount point for plugins which refer to actions that can be performed.
+
+ Plugins implementing this reference should provide the following
+ interface:
+
+ name attribute
+ The text to be displayed, describing the version control system
+ __init__ function
+ Must raise NotAVCSourceTree() if it is not a VCS source tree
+ """
+ __metaclass__ = GenericPluginMeta
+
+ def __init__(self, context):
+ super(VCSourceTree, self).__init__()
+ self.context = context
+
+ @classmethod
+ def detect(cls, srcdir, context):
+ """Detect VCS tree type and return object representing it"""
+ if len(VCSourceTree.plugins) < 1:
+ raise "No VC source tree classes registered"
+ matches = PluginDict()
+ for key, klass in VCSourceTree.plugins.items():
+ try:
+ t = klass(srcdir, context)
+ if t.tree_root() == srcdir:
+ matches[key] = t
+ except NotAVCSourceTree, e:
+ pass
+ if len(matches) > 1:
+ raise AmbigousVCSource(srcdir, matches.values())
+ elif len(matches) < 1:
+ raise NotAVCSourceTree(srcdir)
+ return matches[matches.keys()[0]]
+
+ def get_config(self):
+ """Get configuration object which determines builddir etc"""
+ return AbstractConfig(self.tree_root(), self.branch_name())
+ config = property(get_config)
+
+ def tree_root(self):
+ """Get absolute path to source tree root"""
+ raise NotImplementedError()
+
+ def branch_name(self):
+ """Return name identifying the branch"""
+ raise NotImplementedError()
+
+ def __str__(self):
+ return repr(self)
+
+ def __repr__(self):
+ return "<%s(%s, %s)>" % (self.__class__.__name__,
+ repr(self.tree_root()),
+ repr(self.branch_name()))
+
+
+########################################################################
+# VCS Source Tree plugins
+########################################################################
+
+class GitSourceTree(VCSourceTree):
+
+ name = 'git'
+
+ def __init__(self, srcdir, context):
+ super(GitSourceTree, self).__init__(context)
+ os.chdir(srcdir)
+ if "true" != prog_stdout(["git", "rev-parse",
+ "--is-inside-work-tree"]):
+ raise NotAVCSourceTree()
+ reldir = prog_stdout(["git", "rev-parse", "--show-cdup"])
+ if reldir:
+ os.chdir(reldir)
+ self.__tree_root = os.getcwd()
+
+ def get_config(self):
+ return GitConfig(self.tree_root(), self.branch_name())
+ config = property(get_config)
+
+ def tree_root(self):
+ return self.__tree_root
+
+ def branch_name(self):
+ bname = prog_stdout(["git", "symbolic-ref", "HEAD"])
+ refs,heads,branch = bname.split('/')
+ assert(refs=='refs' and heads=='heads')
+ return branch
+
+
+class GitConfig(AbstractConfig):
+ """git config interface"""
+
+ def __init__(self, *args, **kwargs):
+ super(GitConfig, self).__init__(*args, **kwargs)
+
+ def _itemname(self, item): return '.'.join((GIT_CONFIG_PREFIX, item, ))
+ def _myreldir(self, rdir):
+ return os.path.join(self._srcdir, rdir, self._nick)
+
+ def get_builddir(self):
+ ret, stdout, stderr = prog_retstd(['git', 'config', self._itemname('builddir')])
+ assert(stderr == "")
+ if ret == 0 and stdout:
+ return self._myreldir(stdout)
+ else:
+ return super(GitConfig, self).get_builddir()
+
+ def set_builddir(self, value):
+ ret, stdout, stderr = prog_retstd(['git', 'config', self._itemname('builddir'), value])
+ assert(ret == 0 and stdout == "" and stderr == "")
+
+ builddir = property(get_builddir, set_builddir)
+
+ def get_installdir(self):
+ ret, stdout, stderr = prog_retstd(['git', 'config', self._itemname('installdir')])
+ assert(stderr == "")
+ if ret == 0 and stdout:
+ return self._myreldir(stdout)
+ else:
+ return super(GitConfig, self).get_installdir()
+
+ def set_installdir(self, value):
+ ret, stdout, stderr = prog_retstd(['git', 'config', self._itemname('installdir'), value])
+ assert(ret == 0 and stdout == "" and stderr == "")
+
+ installdir = property(get_installdir, set_installdir)
+
+
+class BzrSourceTree(VCSourceTree):
+
+ name = 'bzr'
+
+ def __init__(self, srcdir, context):
+ super(BzrSourceTree, self).__init__(context)
+ try:
+ import bzrlib.workingtree
+ wt,b = bzrlib.workingtree.WorkingTree.open_containing(srcdir)
+ except bzrlib.errors.NotBranchError:
+ raise NotAVCSourceTree()
+ except ImportError:
+ raise NotAVCSourceTree()
+ self.wt = wt
+ #print "wt:", wt
+ #print "wt:", dir(wt)
+ #print "wt.branch:", wt.branch
+ #print "wt.branch:", dir(wt.branch)
+ #print "wt.branch.nick:", wt.branch.nick
+ #print "wt.branch.abspath:", wt.branch.abspath
+ #print "wt.branch.base:", wt.branch.base
+ #print "wt.branch.basis_tree:", wt.branch.basis_tree()
+
+ def tree_root(self):
+ proto,host,path,some,thing = urlparse.urlsplit(self.wt.branch.base)
+ assert(proto == "file" and host == "")
+ assert(some == "" and thing == "")
+ return os.path.abspath(path)
+
+ def branch_name(self):
+ return self.wt.branch.nick
+
+