Merge John.
[jelmer/dulwich.git] / bin / dulwich
1 #!/usr/bin/python
2 # dul-daemon - Simple git smart server client
3 # Copyright (C) 2008 Jelmer Vernooij <jelmer@samba.org>
4
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; version 2
8 # or (at your option) a later version of the License.
9
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # MA  02110-1301, USA.
19
20 import sys
21 from getopt import getopt
22
23 def get_transport_and_path(uri):
24     from dulwich.client import TCPGitClient, SSHGitClient, SubprocessGitClient
25     for handler, transport in (("git://", TCPGitClient), ("git+ssh://", SSHGitClient)):
26         if uri.startswith(handler):
27             host, path = uri[len(handler):].split("/", 1)
28             return transport(host), "/"+path
29     # if its not git or git+ssh, try a local url..
30     return SubprocessGitClient(), uri
31
32 def cmd_fetch_pack(args):
33         from dulwich.client import SimpleFetchGraphWalker
34         from dulwich.repo import Repo
35         opts, args = getopt(args, "", ["all"])
36         opts = dict(opts)
37         client, path = get_transport_and_path(args.pop(0))
38         if "--all" in opts:
39                 determine_wants = lambda x: [y for y in x.values() if not y in r.object_store]
40         else:
41                 determine_wants = lambda x: [y for y in args if not y in r.object_store]
42         r = Repo(".")
43         graphwalker = SimpleFetchGraphWalker(r.heads().values(), r.get_parents)
44         f, commit = r.object_store.add_pack()
45         try:
46                 client.fetch_pack(path, determine_wants, graphwalker, f.write, sys.stdout.write)
47                 f.close()
48                 commit()
49         except:
50                 f.close()
51                 raise
52
53
54 def cmd_log(args):
55         from dulwich.repo import Repo
56         opts, args = getopt(args, "", [])
57         r = Repo(".")
58         todo = [r.head()]
59         done = set()
60         while todo:
61                 sha = todo.pop()
62                 assert isinstance(sha, str)
63                 if sha in done:
64                         continue
65                 done.add(sha)
66                 commit = r.commit(sha)
67                 print "-" * 50
68                 print "commit: %s" % sha
69                 if len(commit.parents) > 1:
70                         print "merge: %s" % "...".join(commit.parents[1:])
71                 print "author: %s" % commit.author
72                 print "committer: %s" % commit.committer
73                 print ""
74                 print commit.message
75                 print ""
76                 todo.extend([p for p in commit.parents if p not in done])
77
78
79 def cmd_dump_pack(args):
80         from dulwich.errors import ApplyDeltaError
81         from dulwich.pack import Pack, sha_to_hex
82         import os
83         import sys
84
85         opts, args = getopt(args, "", [])
86
87         if args == []:
88                 print "Usage: dulwich dump-pack FILENAME"
89                 sys.exit(1)
90
91         basename, _ = os.path.splitext(args[0])
92         x = Pack(basename)
93         print "Object names checksum: %s" % x.name()
94         print "Checksum: %s" % sha_to_hex(x.get_stored_checksum())
95         if not x.check():
96                 print "CHECKSUM DOES NOT MATCH"
97         print "Length: %d" % len(x)
98         for name in x:
99                 try:
100                         print "\t%s" % x[name]
101                 except KeyError, k:
102                         print "\t%s: Unable to resolve base %s" % (name, k)
103                 except ApplyDeltaError, e:
104                         print "\t%s: Unable to apply delta: %r" % (name, e)
105
106
107 def cmd_dump_index(args):
108         from dulwich.index import Index
109
110         opts, args = getopt(args, "", [])
111
112         if args == []:
113                 print "Usage: dulwich dump-pack FILENAME"
114                 sys.exit(1)
115
116         filename = args[0]
117         idx = Index(filename)
118
119         for o in idx:
120                 print o[0]
121
122
123 def cmd_init(args):
124         from dulwich.repo import Repo
125         import os
126         import sys
127         opts, args = getopt(args, "", ["--bare"])
128         opts = dict(opts)
129
130         if args == []:
131                 path = os.getcwd()
132         else:
133                 path = args[0]
134
135         if not os.path.exists(path):
136                 os.mkdir(path)
137
138         if "--bare" in opts:
139                 Repo.init_bare(path)
140         else:
141                 Repo.init(path)
142
143
144 def cmd_clone(args):
145         from dulwich.client import SimpleFetchGraphWalker
146         from dulwich.repo import Repo
147         import os
148         import sys
149         opts, args = getopt(args, "", [])
150         opts = dict(opts)
151
152         if args == []:
153                 print "usage: dulwich clone host:path [PATH]"
154                 sys.exit(1)
155
156         client, host_path = get_transport_and_path(args.pop(0))
157
158         if len(args) > 0:
159                 path = args.pop(0)
160         else:
161                 path = host_path.split("/")[-1]
162
163         if not os.path.exists(path):
164                 os.mkdir(path)
165         Repo.init(path)
166         r = Repo(path)
167         determine_wants = lambda x: [y for y in x.values() if not y in r.object_store]
168         graphwalker = SimpleFetchGraphWalker(r.heads().values(), r.get_parents)
169         f, commit = r.object_store.add_pack()
170         try:
171                 client.fetch_pack(host_path, determine_wants, graphwalker, f.write, 
172                                           sys.stdout.write)
173                 f.close()
174                 commit()
175         except:
176                 f.close()
177                 raise
178
179
180 commands = {
181         "fetch-pack": cmd_fetch_pack,
182         "dump-pack": cmd_dump_pack,
183         "dump-index": cmd_dump_index,
184         "init": cmd_init,
185         "log": cmd_log,
186         "clone": cmd_clone,
187         }
188
189 if len(sys.argv) < 2:
190         print "Usage: %s <%s> [OPTIONS...]" % (sys.argv[0], "|".join(commands.keys()))
191         sys.exit(1)
192
193 cmd = sys.argv[1]
194 if not cmd in commands:
195         print "No such subcommand: %s" % cmd
196         sys.exit(1)
197 commands[cmd](sys.argv[2:])