-#!/usr/bin/python
-# dul-daemon - Simple git smart server client
-# Copyright (C) 2008 Jelmer Vernooij <jelmer@samba.org>
-#
+#!/usr/bin/python -u
+#
+# dulwich - Simple command-line interface to Dulwich
+# Copyright (C) 2008-2011 Jelmer Vernooij <jelmer@samba.org>
+# vim: expandtab
+#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; version 2
# or (at your option) a later version of the License.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
+"""Simple command-line interface to Dulwich>
+
+This is a very simple command-line wrapper for Dulwich. It is by
+no means intended to be a full-blown Git command-line interface but just
+a way to test Dulwich.
+"""
+
+import os
import sys
from getopt import getopt
-def get_transport_and_path(uri):
- from dulwich.client import TCPGitClient, SSHGitClient, SubprocessGitClient
- for handler, transport in (("git://", TCPGitClient), ("git+ssh://", SSHGitClient)):
- if uri.startswith(handler):
- host, path = uri[len(handler):].split("/", 1)
- return transport(host), "/"+path
- # if its not git or git+ssh, try a local url..
- return SubprocessGitClient(), uri
+from dulwich import porcelain
+from dulwich.client import get_transport_and_path
+from dulwich.errors import ApplyDeltaError
+from dulwich.index import Index
+from dulwich.pack import Pack, sha_to_hex
+from dulwich.patch import write_tree_diff
+from dulwich.repo import Repo
+
+
+def cmd_archive(args):
+ opts, args = getopt(args, "", [])
+ client, path = get_transport_and_path(args.pop(0))
+ location = args.pop(0)
+ committish = args.pop(0)
+ porcelain.archive(location, committish, outstream=sys.stdout,
+ errstream=sys.stderr)
+
+
+def cmd_add(args):
+ opts, args = getopt(args, "", [])
+
+ porcelain.add(".", paths=args)
def cmd_fetch_pack(args):
- from dulwich.client import SimpleFetchGraphWalker
- from dulwich.repo import Repo
- opts, args = getopt(args, "", ["all"])
- opts = dict(opts)
- client, path = get_transport_and_path(args.pop(0))
- if "--all" in opts:
- determine_wants = r.object_store.determine_wants_all
- else:
- determine_wants = lambda x: [y for y in args if not y in r.object_store]
- r = Repo(".")
- graphwalker = SimpleFetchGraphWalker(r.heads().values(), r.get_parents)
- f, commit = r.object_store.add_pack()
- try:
- client.fetch_pack(path, determine_wants, graphwalker, f.write, sys.stdout.write)
- f.close()
- commit()
- except:
- f.close()
- raise
+ opts, args = getopt(args, "", ["all"])
+ opts = dict(opts)
+ client, path = get_transport_and_path(args.pop(0))
+ r = Repo(".")
+ if "--all" in opts:
+ determine_wants = r.object_store.determine_wants_all
+ else:
+ determine_wants = lambda x: [y for y in args if not y in r.object_store]
+ client.fetch(path, r, determine_wants)
+
+
+def cmd_fetch(args):
+ opts, args = getopt(args, "", [])
+ opts = dict(opts)
+ client, path = get_transport_and_path(args.pop(0))
+ r = Repo(".")
+ if "--all" in opts:
+ determine_wants = r.object_store.determine_wants_all
+ refs = client.fetch(path, r, progress=sys.stdout.write)
+ print "Remote refs:"
+ for item in refs.iteritems():
+ print "%s -> %s" % item
def cmd_log(args):
- from dulwich.repo import Repo
- opts, args = getopt(args, "", [])
- r = Repo(".")
- todo = [r.head()]
- done = set()
- while todo:
- sha = todo.pop()
- assert isinstance(sha, str)
- if sha in done:
- continue
- done.add(sha)
- commit = r.commit(sha)
- print "-" * 50
- print "commit: %s" % sha
- if len(commit.parents) > 1:
- print "merge: %s" % "...".join(commit.parents[1:])
- print "author: %s" % commit.author
- print "committer: %s" % commit.committer
- print ""
- print commit.message
- print ""
- todo.extend([p for p in commit.parents if p not in done])
+ opts, args = getopt(args, "", [])
+ if len(args) > 0:
+ path = args.pop(0)
+ else:
+ path = "."
+ r = Repo(path)
+ todo = [r.head()]
+ done = set()
+ while todo:
+ sha = todo.pop()
+ assert isinstance(sha, str)
+ if sha in done:
+ continue
+ done.add(sha)
+ commit = r[sha]
+ print "-" * 50
+ print "commit: %s" % sha
+ if len(commit.parents) > 1:
+ print "merge: %s" % "...".join(commit.parents[1:])
+ print "author: %s" % commit.author
+ print "committer: %s" % commit.committer
+ print ""
+ print commit.message
+ print ""
+ todo.extend([p for p in commit.parents if p not in done])
+
+
+def cmd_diff(args):
+ opts, args = getopt(args, "", [])
+
+ if args == []:
+ print "Usage: dulwich diff COMMITID"
+ sys.exit(1)
+
+ r = Repo(".")
+ commit_id = args[0]
+ commit = r[commit_id]
+ parent_commit = r[commit.parents[0]]
+ write_tree_diff(sys.stdout, r.object_store, parent_commit.tree, commit.tree)
def cmd_dump_pack(args):
- from dulwich.errors import ApplyDeltaError
- from dulwich.pack import Pack, sha_to_hex
- import os
- import sys
-
- opts, args = getopt(args, "", [])
-
- if args == []:
- print "Usage: dulwich dump-pack FILENAME"
- sys.exit(1)
-
- basename, _ = os.path.splitext(args[0])
- x = Pack(basename)
- print "Object names checksum: %s" % x.name()
- print "Checksum: %s" % sha_to_hex(x.get_stored_checksum())
- if not x.check():
- print "CHECKSUM DOES NOT MATCH"
- print "Length: %d" % len(x)
- for name in x:
- try:
- print "\t%s" % x[name]
- except KeyError, k:
- print "\t%s: Unable to resolve base %s" % (name, k)
- except ApplyDeltaError, e:
- print "\t%s: Unable to apply delta: %r" % (name, e)
+ opts, args = getopt(args, "", [])
+
+ if args == []:
+ print "Usage: dulwich dump-pack FILENAME"
+ sys.exit(1)
+
+ basename, _ = os.path.splitext(args[0])
+ x = Pack(basename)
+ print "Object names checksum: %s" % x.name()
+ print "Checksum: %s" % sha_to_hex(x.get_stored_checksum())
+ if not x.check():
+ print "CHECKSUM DOES NOT MATCH"
+ print "Length: %d" % len(x)
+ for name in x:
+ try:
+ print "\t%s" % x[name]
+ except KeyError, k:
+ print "\t%s: Unable to resolve base %s" % (name, k)
+ except ApplyDeltaError, e:
+ print "\t%s: Unable to apply delta: %r" % (name, e)
def cmd_dump_index(args):
- from dulwich.index import Index
-
- opts, args = getopt(args, "", [])
+ opts, args = getopt(args, "", [])
- if args == []:
- print "Usage: dulwich dump-pack FILENAME"
- sys.exit(1)
+ if args == []:
+ print "Usage: dulwich dump-index FILENAME"
+ sys.exit(1)
- filename = args[0]
- idx = Index(filename)
+ filename = args[0]
+ idx = Index(filename)
- for o in idx:
- print o[0]
+ for o in idx:
+ print o, idx[o]
def cmd_init(args):
- from dulwich.repo import Repo
- import os
- import sys
- opts, args = getopt(args, "", ["--bare"])
- opts = dict(opts)
+ opts, args = getopt(args, "", ["bare"])
+ opts = dict(opts)
- if args == []:
- path = os.getcwd()
- else:
- path = args[0]
+ if args == []:
+ path = os.getcwd()
+ else:
+ path = args[0]
- if not os.path.exists(path):
- os.mkdir(path)
-
- if "--bare" in opts:
- Repo.init_bare(path)
- else:
- Repo.init(path)
+ porcelain.init(path, bare=("--bare" in opts))
def cmd_clone(args):
- from dulwich.client import SimpleFetchGraphWalker
- from dulwich.repo import Repo
- import os
- import sys
- opts, args = getopt(args, "", [])
- opts = dict(opts)
-
- if args == []:
- print "usage: dulwich clone host:path [PATH]"
- sys.exit(1)
- client, host_path = get_transport_and_path(args.pop(0))
-
- if len(args) > 0:
- path = args.pop(0)
- else:
- path = host_path.split("/")[-1]
-
- if not os.path.exists(path):
- os.mkdir(path)
- Repo.init(path)
- r = Repo(path)
- graphwalker = SimpleFetchGraphWalker(r.heads().values(), r.get_parents)
- f, commit = r.object_store.add_pack()
- client.fetch_pack(host_path, r.object_store.determine_wants_all,
- graphwalker, f.write, sys.stdout.write)
- commit()
+ opts, args = getopt(args, "", ["bare"])
+ opts = dict(opts)
+
+ if args == []:
+ print "usage: dulwich clone host:path [PATH]"
+ sys.exit(1)
+
+ source = args.pop(0)
+ if len(args) > 0:
+ target = args.pop(0)
+ else:
+ target = None
+
+ porcelain.clone(source, target, bare=("--bare" in opts))
+
+
+def cmd_commit(args):
+ opts, args = getopt(args, "", ["message"])
+ opts = dict(opts)
+ porcelain.commit(".", message=opts["--message"])
+
+
+def cmd_update_server_info(args):
+ porcelain.update_server_info(".")
commands = {
- "fetch-pack": cmd_fetch_pack,
- "dump-pack": cmd_dump_pack,
- "dump-index": cmd_dump_index,
- "init": cmd_init,
- "log": cmd_log,
- "clone": cmd_clone,
- }
+ "commit": cmd_commit,
+ "fetch-pack": cmd_fetch_pack,
+ "fetch": cmd_fetch,
+ "dump-pack": cmd_dump_pack,
+ "dump-index": cmd_dump_index,
+ "init": cmd_init,
+ "log": cmd_log,
+ "clone": cmd_clone,
+ "archive": cmd_archive,
+ "update-server-info": cmd_update_server_info,
+ "diff": cmd_diff,
+ }
if len(sys.argv) < 2:
- print "Usage: %s <%s> [OPTIONS...]" % (sys.argv[0], "|".join(commands.keys()))
- sys.exit(1)
+ print "Usage: %s <%s> [OPTIONS...]" % (sys.argv[0], "|".join(commands.keys()))
+ sys.exit(1)
cmd = sys.argv[1]
if not cmd in commands:
- print "No such subcommand: %s" % cmd
- sys.exit(1)
+ print "No such subcommand: %s" % cmd
+ sys.exit(1)
commands[cmd](sys.argv[2:])