#!/usr/bin/env python """cmt_svn_checkout.py: Checkout CMT package(s) from Subversion repository. Usage: cmt_svn_checkout.py [OPTION]... PATH... Checkout PATH(s) relative to or being Subversion repository URL(s). Mandatory arguments to long options are mandatory for short options too. -r, --version-tag=REV checkout version tag REV of PATH --version-dir=DIR use DIR as version directory instead of version tag -d, --directory=DIR checkout into DIR instead of (basename of) PATH -o, --offset=OFFSET checkout PATH at OFFSET relative to repository URL --no_config disable config step upon checkout --without_version_directory do not create version directory upon PATH checkout --with_version_directory create version directory upon PATH checkout (default) --url=URL checkout PATH from repository URL -h, --help display this help and exit --version output version information and exit The SVNROOT, SVNTRUNK, SVNTAGS, and SVNBRANCHES environment variables specify repository URL of PATH, location of PATH trunk, tags, and branches (relatively to PATH) respectively. Report bugs to . """ __version__ = '0.1.5' __date__ = 'Tue May 05 2009' __author__ = 'Grigory Rybkin' import sys import getopt import os import posixpath import os.path import urlparse self = 'cmt_svn_checkout.py' try: from svn import client, core except ImportError, e: print >>sys.stderr, '%s: cannot import Subversion Python bindings: %s' \ % (self, str(e)) sys.exit(1) class ClientContext(object): def __init__(self): core.svn_config_ensure(None) self.ctx = client.create_context() self.providers = [ client.get_simple_provider(), client.get_username_provider(), client.get_ssl_server_trust_file_provider(), client.get_ssl_client_cert_file_provider(), client.get_ssl_client_cert_pw_file_provider() ] self.ctx.auth_baton = core.svn_auth_open(self.providers) self.ctx.config = core.svn_config_get_config(None) def __call__(self): return self.ctx def cwd(): _gcwd = os.getcwd() try: _cwd = os.environ['PWD'] if _cwd and os.path.samefile(_cwd, _gcwd): return _cwd else: return _gcwd except (KeyError, AttributeError): return _gcwd def cd(path): new = os.path.normpath(os.path.join(cwd(), path)) os.chdir(path) _gcwd = os.getcwd() try: if os.path.samefile(new, _gcwd): os.environ['PWD'] = new else: os.environ['PWD'] = _gcwd except AttributeError: pass def error(instance, location='', file = sys.stderr): try: message = ': '.join([str(arg) for arg in instance.args]) except AttributeError: message = instance if location: location += ': ' print >> file, "%s%s" % (location, message) class CmtContext(object): def __init__(self, config = True, with_version_directory = True, cleanup = False): self.config = config self.with_version_directory = with_version_directory self.cleanup = cleanup def write(self, p, version): #print >> sys.stderr, 'write:', p, version try: t = version + '\n' if os.path.exists(p): f = open(p, 'r+') b = f.tell() v = f.read() if v != t: f.seek(b) f.write(t) f.truncate() else: f = open(p, 'w') f.write(t) f.close() except IOError, e: print >> sys.stderr, e return 1 return 0 def generate(self, p): #print >> sys.stderr, 'generate:', p curdir = cwd() cmd = 'cmt -disable_warnings' if self.with_version_directory: cmd += ' -with_version_directory' else: cmd += ' -without_version_directory' if self.cleanup: cmd += ' -cleanup' else: cmd += ' -no_cleanup' cmd += ' config' cd(p) sc = os.system(cmd) if sc != 0: sc = 1 cd(curdir) return sc def configure(self, path, version): sc = 0 for d in ('cmt', 'mgr'): p = os.path.join(path, d) if os.path.isdir(p): if not self.with_version_directory: sc += self.write(os.path.join(p,'version.cmt'), version) if self.config: sc += self.generate(p) return sc return sc #print >> sys.stderr, 'Cannot configure %s ' % (path, version) class Module(object): def __init__(self, module): self.module = module self.init = False class Checkout(object): def __init__(self, url = None, trunk = None, tags = None, branches = None, version = None, version_dir = None, directory = None, offset = None, modules = []): self.url = url self.trunk = trunk self.tags = tags self.branches = branches self.version = version self.version_dir = version_dir self.directory = directory self.offset = offset self.modules = modules self.reposLayout() def reposLayout(self): if self.url is None: try: self.url = os.environ['SVNROOT'] except KeyError: pass if self.trunk is None: try: self.trunk = os.environ['SVNTRUNK'] except KeyError: self.trunk = 'trunk' if self.tags is None: try: self.tags = os.environ['SVNTAGS'] except KeyError: self.tags = 'tags' if self.branches is None: try: self.branches = os.environ['SVNBRANCHES'] except KeyError: self.branches = 'branches' def cmtRepos(self): self.url = 'https://svn.lal.in2p3.fr/projects/CMT' self.trunk = 'HEAD' self.tags= '.' self.branches = '.' def add(self, module): self.modules.append(module) def initialize(self, cmt_context, client_context): sc = 0 self.head_revision = core.svn_opt_revision_t() self.head_revision.kind = core.svn_opt_revision_head for m in self.modules: if urlparse.urlparse(m.module)[0] in ('http', 'https', 'svn', 'svn+ssh', 'file'): m.url = m.module m.path = posixpath.basename(m.module) elif posixpath.isabs(m.module): m.url = urlparse.urljoin('file://', m.module) m.path = posixpath.basename(m.module) else: if self.url is None: self.cmtRepos() if self.offset is None: m.url = posixpath.join(self.url, m.module) else: m.url = posixpath.join(self.url, self.offset, m.module) m.path = os.path.join(*m.module.split(posixpath.sep)) if self.directory is not None: m.path = os.path.normpath(self.directory) if self.version is None: m.head = True tags = core.svn_path_canonicalize(posixpath.join(m.url, self.tags)) try: #print 'client.ls2:', tags ls_tags = client.ls2(tags, self.head_revision, self.head_revision, False, client_context()) rev_tag = dict([(ls_tags[p].created_rev, p) for p in ls_tags if ls_tags[p].kind == core.svn_node_dir]) # rev_latest = max(rev_tag.keys()) # tag_latest = rev_tag[rev_latest] m.version = rev_tag[max(rev_tag.keys())] except core.SubversionException, e: error(e) #print >> sys.stderr, e m.version = 'HEAD' except ValueError, e: # max() arg is an empty sequence #print >> sys.stderr, e m.version = 'HEAD' else: m.head = False m.version = self.version if m.head: m.URL = [posixpath.join(m.url, self.trunk)] else: # m.url = posixpath.join(m.url, self.tags, m.version) m.URL = [posixpath.join(m.url, p, m.version) for p in (self.tags, self.branches)] #m.URL = [posixpath.join(m.url, self.tags, m.version), # posixpath.join(m.url, self.branches, m.version)] #m.url = core.svn_path_canonicalize(m.url) m.URL = [core.svn_path_canonicalize(url) for url in m.URL] if cmt_context.with_version_directory: if self.version_dir is None: m.path = os.path.join(m.path, m.version) else: m.path = os.path.join(m.path, self.version_dir) m.init = True # print m.URL, m.path, m.init # for m in self.modules: # print m.url, m.path, m.init return sc def execute(self, cmt_context, client_context): sc = 0 for m in self.modules: if not m.init: continue done = False err = [] for url in m.URL: try: #print 'client.checkout2:', url, m.path result_rev = client.checkout2(url, m.path, self.head_revision, self.head_revision, True, True, client_context()) except core.SubversionException, e: err.append(e) continue done = True break if not done: for e in err: error(e) #print >> sys.stderr, e sc += 1 continue # print 'Checked out revision %i.' % result_rev scc = cmt_context.configure(m.path, m.version) if scc != 0: print >> sys.stderr, \ '%s %s: configure returned %i.' % (m.path, m.version, scc) sc += scc return sc def main(argv=[__name__]): self = os.path.basename(argv[0]) try: opts, args = getopt.getopt(argv[1:], "hr:d:o:", ["help", "version", "version-tag=", "version-dir=", "directory=", "offset=", "no_config", "with_version_directory", "without_version_directory", "url="]) except getopt.error, e: print >>sys.stderr, '%s: %s' % (self, str(e)) print >>sys.stderr, "Try '%s --help' for more information." % self return 1 cmt_context = CmtContext() checkout = Checkout() for o, v in opts: if o in ("-h", "--help"): print sys.modules[__name__].__doc__ return 0 elif o in ("--version",): print '%s %s (%s)' % (self, __version__, __date__) print '%sWritten by %s.' % (os.linesep, __author__) return 0 elif o in ("-r", "--version-tag"): checkout.version = v elif o in ("--version-dir",): checkout.version_dir = v elif o in ("-d", "--directory"): checkout.directory = v elif o in ("-o", "--offset"): checkout.offset = v elif o in ("--no_config",): cmt_context.config = False elif o in ("--without_version_directory",): cmt_context.with_version_directory = False elif o in ("--with_version_directory",): cmt_context.with_version_directory = True elif o in ("--url",): checkout.url = v if not args: print >>sys.stderr, '%s: missing path argument' % self print >>sys.stderr, "Try '%s --help' for more information." % self return 1 for arg in args: checkout.add(Module(arg)) client_context = ClientContext() sci = checkout.initialize(cmt_context, client_context) sce = checkout.execute(cmt_context, client_context) if sci != 0 or sce !=0: return 1 else: return 0 if __name__ == '__main__': sys.exit(main(sys.argv))