1########################################################################## 2# Copyright (c) 2009, ETH Zurich. 3# All rights reserved. 4# 5# This file is distributed under the terms in the attached LICENSE file. 6# If you do not find this file, copies can be found by writing to: 7# ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 8########################################################################## 9 10try: 11 from mercurial import hg, ui, node, error, commands 12 mercurial_module = True 13except ImportError: 14 mercurial_module = False 15 16try: 17 import git 18 git_module = True 19except ImportError: 20 git_module = False 21 22class Checkout(object): 23 '''Checkout Base class: 24 Maintain information about revision number, and directory locations 25 ''' 26 27 def __init__(self, base_dir): 28 # Set parameters 29 self.base_dir = base_dir 30 31 def get_base_dir(self): 32 return self.base_dir 33 34 ''' Returns a unique commit identifier as string ''' 35 def get_revision(self): 36 return '(repository information/git/hg module not available)' 37 38 ''' Return a string (or None) containing a patch file representing local changes''' 39 def get_diff(self): 40 return None 41 42 ''' Return a dict of additional info ''' 43 def get_meta(self): 44 return {} 45 46 47class CheckoutHg(Checkout): 48 def __init__(self, base_dir, repo): 49 super(CheckoutHg, self).__init__(base_dir) 50 self.repo = repo 51 52 def get_revision(self): 53 # identify the parents of the working revision 54 context = self.repo[None] 55 parents = context.parents() 56 s = ', '.join(map(lambda p: node.short(p.node()), parents)) 57 if context.files() or context.deleted(): 58 s += ' with local changes' 59 else: 60 s += ' unmodified' 61 return s 62 63 64 def get_diff(self): 65 context = self.repo[None] 66 if not context.files() and not context.deleted(): 67 return None 68 69 diffui = ui.ui() 70 diffui.pushbuffer() 71 commands.diff(diffui, self.repo, git=True) 72 return diffui.popbuffer() 73 74class CheckoutGit(Checkout): 75 def __init__(self, base_dir, repo): 76 super(CheckoutGit, self).__init__(base_dir) 77 self.repo = repo 78 79 def get_diff(self): 80 gitc = self.repo.git 81 return gitc.diff() + "\n\n" + gitc.diff(cached=True) 82 83 def get_revision(self): 84 return self.repo.head.commit.hexsha 85 86 def get_meta(self): 87 repo = self.repo 88 headc = repo.head.commit 89 ret = {} 90 shortsha = self.repo.git.rev_parse(headc.hexsha, short=7) 91 try: 92 ret["branch"] = repo.active_branch.name 93 except TypeError, e: 94 ret["branch"] = "(HEAD detached at %s)" % shortsha 95 ret["shortrev"] = shortsha 96 ret["commitmsg"] = headc.message.split("\n")[0] 97 ret["commitmsg-tail"] = "".join(headc.message.split("\n")[1:]) 98 ret["dirty"] = str(self.repo.is_dirty()) 99 ret["untracked-files"] = ",".join(self.repo.untracked_files) 100 return ret 101 102 103 104''' Factory method that checks a directory and instantiates 105the correct Checkout class ''' 106def create_for_dir(base_dir): 107 if git_module: 108 try: 109 return CheckoutGit(base_dir, git.Repo(base_dir)) 110 except git.InvalidGitRepositoryError: 111 pass 112 113 if mercurial_module: 114 try: 115 return CheckoutHg(base_dir, hg.repository(ui.ui(), base_dir)) 116 except error.RepoError: 117 pass 118 119 return Checkout(base_dir) 120 121 122 123