]>
Commit | Line | Data |
---|---|---|
7aeaa2fc SR |
1 | #!/usr/bin/env python |
2 | ||
23b093ee BC |
3 | # hashlib is only available in python >= 2.5 |
4 | try: | |
5 | import hashlib | |
6 | _digest = hashlib.sha1 | |
7 | except ImportError: | |
8 | import sha | |
9 | _digest = sha.new | |
7aeaa2fc | 10 | import sys |
f733f6a0 BG |
11 | import os |
12 | sys.path.insert(0, os.getenv("GITPYTHONLIB",".")) | |
7aeaa2fc SR |
13 | |
14 | from git_remote_helpers.util import die, debug, warn | |
15 | from git_remote_helpers.git.repo import GitRepo | |
16 | from git_remote_helpers.git.exporter import GitExporter | |
17 | from git_remote_helpers.git.importer import GitImporter | |
18 | from git_remote_helpers.git.non_local import NonLocalGit | |
19 | ||
20 | def get_repo(alias, url): | |
21 | """Returns a git repository object initialized for usage. | |
22 | """ | |
23 | ||
24 | repo = GitRepo(url) | |
25 | repo.get_revs() | |
26 | repo.get_head() | |
27 | ||
23b093ee | 28 | hasher = _digest() |
7aeaa2fc SR |
29 | hasher.update(repo.path) |
30 | repo.hash = hasher.hexdigest() | |
31 | ||
32 | repo.get_base_path = lambda base: os.path.join( | |
33 | base, 'info', 'fast-import', repo.hash) | |
34 | ||
35 | prefix = 'refs/testgit/%s/' % alias | |
36 | debug("prefix: '%s'", prefix) | |
37 | ||
38 | repo.gitdir = "" | |
39 | repo.alias = alias | |
40 | repo.prefix = prefix | |
41 | ||
42 | repo.exporter = GitExporter(repo) | |
43 | repo.importer = GitImporter(repo) | |
44 | repo.non_local = NonLocalGit(repo) | |
45 | ||
46 | return repo | |
47 | ||
48 | ||
49 | def local_repo(repo, path): | |
50 | """Returns a git repository object initalized for usage. | |
51 | """ | |
52 | ||
53 | local = GitRepo(path) | |
54 | ||
55 | local.non_local = None | |
56 | local.gitdir = repo.gitdir | |
57 | local.alias = repo.alias | |
58 | local.prefix = repo.prefix | |
59 | local.hash = repo.hash | |
60 | local.get_base_path = repo.get_base_path | |
61 | local.exporter = GitExporter(local) | |
62 | local.importer = GitImporter(local) | |
63 | ||
64 | return local | |
65 | ||
66 | ||
67 | def do_capabilities(repo, args): | |
68 | """Prints the supported capabilities. | |
69 | """ | |
70 | ||
71 | print "import" | |
72 | print "export" | |
73 | print "gitdir" | |
74 | print "refspec refs/heads/*:%s*" % repo.prefix | |
75 | ||
76 | print # end capabilities | |
77 | ||
78 | ||
79 | def do_list(repo, args): | |
80 | """Lists all known references. | |
81 | ||
82 | Bug: This will always set the remote head to master for non-local | |
83 | repositories, since we have no way of determining what the remote | |
84 | head is at clone time. | |
85 | """ | |
86 | ||
87 | for ref in repo.revs: | |
88 | debug("? refs/heads/%s", ref) | |
89 | print "? refs/heads/%s" % ref | |
90 | ||
91 | if repo.head: | |
92 | debug("@refs/heads/%s HEAD" % repo.head) | |
93 | print "@refs/heads/%s HEAD" % repo.head | |
94 | else: | |
95 | debug("@refs/heads/master HEAD") | |
96 | print "@refs/heads/master HEAD" | |
97 | ||
98 | print # end list | |
99 | ||
100 | ||
101 | def update_local_repo(repo): | |
102 | """Updates (or clones) a local repo. | |
103 | """ | |
104 | ||
105 | if repo.local: | |
106 | return repo | |
107 | ||
108 | path = repo.non_local.clone(repo.gitdir) | |
109 | repo.non_local.update(repo.gitdir) | |
110 | repo = local_repo(repo, path) | |
111 | return repo | |
112 | ||
113 | ||
114 | def do_import(repo, args): | |
115 | """Exports a fast-import stream from testgit for git to import. | |
116 | """ | |
117 | ||
118 | if len(args) != 1: | |
119 | die("Import needs exactly one ref") | |
120 | ||
121 | if not repo.gitdir: | |
122 | die("Need gitdir to import") | |
123 | ||
124 | repo = update_local_repo(repo) | |
125 | repo.exporter.export_repo(repo.gitdir) | |
126 | ||
127 | ||
128 | def do_export(repo, args): | |
129 | """Imports a fast-import stream from git to testgit. | |
130 | """ | |
131 | ||
132 | if not repo.gitdir: | |
133 | die("Need gitdir to export") | |
134 | ||
135 | dirname = repo.get_base_path(repo.gitdir) | |
136 | ||
137 | if not os.path.exists(dirname): | |
138 | os.makedirs(dirname) | |
139 | ||
140 | path = os.path.join(dirname, 'testgit.marks') | |
141 | print path | |
23b093ee BC |
142 | if os.path.exists(path): |
143 | print path | |
144 | else: | |
145 | print "" | |
7aeaa2fc SR |
146 | sys.stdout.flush() |
147 | ||
148 | update_local_repo(repo) | |
149 | repo.importer.do_import(repo.gitdir) | |
150 | repo.non_local.push(repo.gitdir) | |
151 | ||
152 | ||
153 | def do_gitdir(repo, args): | |
154 | """Stores the location of the gitdir. | |
155 | """ | |
156 | ||
157 | if not args: | |
158 | die("gitdir needs an argument") | |
159 | ||
160 | repo.gitdir = ' '.join(args) | |
161 | ||
162 | ||
163 | COMMANDS = { | |
164 | 'capabilities': do_capabilities, | |
165 | 'list': do_list, | |
166 | 'import': do_import, | |
167 | 'export': do_export, | |
168 | 'gitdir': do_gitdir, | |
169 | } | |
170 | ||
171 | ||
172 | def sanitize(value): | |
173 | """Cleans up the url. | |
174 | """ | |
175 | ||
176 | if value.startswith('testgit::'): | |
177 | value = value[9:] | |
178 | ||
179 | return value | |
180 | ||
181 | ||
182 | def read_one_line(repo): | |
183 | """Reads and processes one command. | |
184 | """ | |
185 | ||
186 | line = sys.stdin.readline() | |
187 | ||
188 | cmdline = line | |
189 | ||
190 | if not cmdline: | |
191 | warn("Unexpected EOF") | |
192 | return False | |
193 | ||
194 | cmdline = cmdline.strip().split() | |
195 | if not cmdline: | |
196 | # Blank line means we're about to quit | |
197 | return False | |
198 | ||
199 | cmd = cmdline.pop(0) | |
200 | debug("Got command '%s' with args '%s'", cmd, ' '.join(cmdline)) | |
201 | ||
202 | if cmd not in COMMANDS: | |
203 | die("Unknown command, %s", cmd) | |
204 | ||
205 | func = COMMANDS[cmd] | |
206 | func(repo, cmdline) | |
207 | sys.stdout.flush() | |
208 | ||
209 | return True | |
210 | ||
211 | ||
212 | def main(args): | |
213 | """Starts a new remote helper for the specified repository. | |
214 | """ | |
215 | ||
216 | if len(args) != 3: | |
217 | die("Expecting exactly three arguments.") | |
218 | sys.exit(1) | |
219 | ||
220 | if os.getenv("GIT_DEBUG_TESTGIT"): | |
221 | import git_remote_helpers.util | |
222 | git_remote_helpers.util.DEBUG = True | |
223 | ||
224 | alias = sanitize(args[1]) | |
225 | url = sanitize(args[2]) | |
226 | ||
227 | if not alias.isalnum(): | |
228 | warn("non-alnum alias '%s'", alias) | |
229 | alias = "tmp" | |
230 | ||
231 | args[1] = alias | |
232 | args[2] = url | |
233 | ||
234 | repo = get_repo(alias, url) | |
235 | ||
236 | debug("Got arguments %s", args[1:]) | |
237 | ||
238 | more = True | |
239 | ||
240 | while (more): | |
241 | more = read_one_line(repo) | |
242 | ||
243 | if __name__ == '__main__': | |
244 | sys.exit(main(sys.argv)) |