git-remote-testgit: make local a function
[git/dscho.git] / git_remote_helpers / helper.py
blob20a97b1d96a0da831357390b72c7edd514113e77
1 import os
2 import sys
3 import time
5 # hashlib is only available in python >= 2.5
6 try:
7 import hashlib
8 _digest = hashlib.sha1
9 except ImportError:
10 import sha
11 _digest = sha.new
13 from git_remote_helpers.util import debug, die, warn
16 class RemoteHelper(object):
17 def __init__(self):
18 self.commands = {
19 'capabilities': self.do_capabilities,
20 'list': self.do_list,
21 'import': self.do_import,
22 'export': self.do_export,
25 def setup_repo(self, repo, alias):
26 """Returns a git repository object initialized for usage.
27 """
29 hasher = _digest()
30 hasher.update(repo.path)
31 repo.hash = hasher.hexdigest()
33 repo.get_base_path = lambda base: os.path.join(
34 base, 'info', 'fast-import', repo.hash)
36 repo.gitdir = os.environ["GIT_DIR"]
37 repo.alias = alias
39 def setup_local_repo(self, local, repo):
40 """Returns a git repository object initalized for usage.
41 """
42 local.non_local = None
43 local.gitdir = repo.gitdir
44 local.alias = repo.alias
45 local.prefix = repo.prefix
46 local.hash = repo.hash
47 local.get_base_path = repo.get_base_path
49 def do_capabilities(self, repo, args):
50 """Prints the supported capabilities.
51 """
53 print "import"
54 print "export"
55 print "refspec refs/heads/*:%s*" % repo.prefix
57 dirname = repo.get_base_path(repo.gitdir)
59 if not os.path.exists(dirname):
60 os.makedirs(dirname)
62 path = os.path.join(dirname, repo.marksfile)
64 print "*export-marks %s" % path
65 if os.path.exists(path):
66 print "*import-marks %s" % path
68 print # end capabilities
70 def update_local_repo(self, repo):
71 """Updates (or clones) a local repo.
72 """
74 if repo.local():
75 return repo
77 path = repo.non_local.clone(repo.gitdir)
78 repo.non_local.update(repo.gitdir)
79 repo = self.local_repo(repo, path)
80 return repo
82 def do_import(self, repo, args):
83 """Exports a fast-import stream from testgit for git to import.
84 """
86 if len(args) != 1:
87 die("Import needs exactly one ref")
89 if not repo.gitdir:
90 die("Need gitdir to import")
92 ref = args[0]
93 refs = [ref]
95 while True:
96 line = sys.stdin.readline()
97 if line == '\n':
98 break
99 if not line.startswith('import '):
100 die("Expected import line.")
102 # strip of leading 'import '
103 ref = line[7:].strip()
104 refs.append(ref)
106 repo = self.update_local_repo(repo)
108 repo.exporter.export_repo(repo.gitdir, refs)
110 print "done"
112 def do_export(self, repo, args):
113 """Imports a fast-import stream from git to testgit.
116 if not repo.gitdir:
117 die("Need gitdir to export")
119 localrepo = self.update_local_repo(repo)
121 refs_before = self.get_refs(repo, repo.gitdir)
122 localrepo.importer.do_import(localrepo.gitdir)
123 refs_after = self.get_refs(repo, repo.gitdir)
125 changed = {}
127 for name, value in refs_after.iteritems():
128 if refs_before.get(name) == value:
129 continue
131 changed[name] = value
133 if not repo.local():
134 repo.non_local.push(repo.gitdir)
136 for ref in changed:
137 print "ok %s" % ref
138 print
140 def read_one_line(self, repo):
141 """Reads and processes one command.
144 sleepy = os.environ.get("GIT_REMOTE_TESTGIT_SLEEPY")
145 if sleepy:
146 debug("Sleeping %d sec before readline" % int(sleepy))
147 time.sleep(int(sleepy))
149 line = sys.stdin.readline()
151 cmdline = line
153 if not cmdline:
154 warn("Unexpected EOF")
155 return False
157 cmdline = cmdline.strip().split()
158 if not cmdline:
159 # Blank line means we're about to quit
160 return False
162 cmd = cmdline.pop(0)
163 debug("Got command '%s' with args '%s'", cmd, ' '.join(cmdline))
165 if cmd not in self.commands:
166 die("Unknown command, %s", cmd)
168 func = self.commands[cmd]
169 func(repo, cmdline)
170 sys.stdout.flush()
172 return True
174 def main(self, args):
175 """Starts a new remote helper for the specified repository.
178 if len(args) != 3:
179 die("Expecting exactly three arguments.")
180 sys.exit(1)
182 if os.getenv("GIT_REMOTE_HELPER_DEBUG"):
183 import git_remote_helpers.util
184 git_remote_helpers.util.DEBUG = True
186 alias = self.sanitize(args[1])
187 url = self.sanitize(args[2])
189 if not alias.isalnum():
190 warn("non-alnum alias '%s'", alias)
191 alias = "tmp"
193 args[1] = alias
194 args[2] = url
196 repo = self.get_repo(alias, url)
198 debug("Got arguments %s", args[1:])
200 more = True
202 sys.stdin = os.fdopen(sys.stdin.fileno(), 'r', 0)
203 while (more):
204 more = self.read_one_line(repo)
206 if __name__ == '__main__':
207 sys.exit(main(sys.argv))