# # # patch "dumb.py" # from [55d192751b75c11a4baec50cbce2f1f705fb2842] # to [db3bcb120be2dc532f347c961ca6fa08bff72732] # # patch "fs.py" # from [0741851af22991c3a1faf7345c8b85ab3b4c5a9f] # to [d872e4820e299bb0b72296f54fdb54ee1725907b] # # patch "fs_sftp.py" # from [c31b2800f0333335f2b4a9d6f8075563ad30bd1b] # to [c298681baed4855de43c8668b88ce94a8b6cee73] # # patch "monotone.py" # from [2011146c9195c7156ab56b6e3f93d193b6b95a29] # to [875e49730a651ade4a72c6685e6dee84afe68ec1] # ============================================================ --- dumb.py 55d192751b75c11a4baec50cbce2f1f705fb2842 +++ dumb.py db3bcb120be2dc532f347c961ca6fa08bff72732 @@ -6,7 +6,6 @@ from merkle_dir import MerkleDir, LockError from fs import readable_fs_for_url, writeable_fs_for_url from monotone import Monotone -import zlib class Dumbtone: @@ -29,17 +28,8 @@ self.monotone.ensure_db() md = MerkleDir(readable_fs_for_url(url)) feeder = self.monotone.feeder(self.verbosity) - if self.verbosity > 1: - # verbose op, splits the chunk in the individual packets, - # and reads them one by one - for id, data in md.all_chunks(): - uncdata = zlib.decompress(data) - for pkt in uncdata.split("[end]"): - if len(pkt)>1: - feeder.write(pkt+"[end]") - else: - for id, data in md.all_chunks(): - feeder.write(zlib.decompress(data)) + for id, data in md.all_chunks(): + feeder.write(data) feeder.close() def do_export(self, url): @@ -119,30 +109,22 @@ self.feeder = feeder def __call__(self, id, data): self.added += 1 - if self.feeder.verbosity > 1: - # verbose op, splits the chunk in the individual packets, - # and reads them one by one - uncdata = zlib.decompress(data) - for pkt in uncdata.split("[end]"): - if len(pkt)>1: - self.feeder.write(pkt+"[end]") - else: - self.feeder.write(zlib.decompress(data)) + self.feeder.write(data) - def do_push(self, local_url, target_url): + def do_push(self, local_url, target_url, **kwargs): print "Exporting changes from monotone db to %s" % (local_url,) self.do_export(local_url) print "Pushing changes from %s to %s" % (local_url, target_url) - local_md = MerkleDir(readable_fs_for_url(local_url)) - target_md = MerkleDir(writeable_fs_for_url(target_url)) + local_md = MerkleDir(readable_fs_for_url(local_url, **kwargs)) + target_md = MerkleDir(writeable_fs_for_url(target_url, **kwargs)) c = Dumbtone.CounterCallback() local_md.push(target_md, c) print "Pushed %s packets to %s" % (c.added, target_url) - def do_pull(self, local_url, source_url): + def do_pull(self, local_url, source_url, **kwargs): print "Pulling changes from %s to %s" % (source_url, local_url) - local_md = MerkleDir(writeable_fs_for_url(local_url)) - source_md = MerkleDir(readable_fs_for_url(source_url)) + local_md = MerkleDir(writeable_fs_for_url(local_url, **kwargs)) + source_md = MerkleDir(readable_fs_for_url(source_url, **kwargs)) self.monotone.ensure_db() feeder = self.monotone.feeder(self.verbosity) fc = Dumbtone.FeederCallback(feeder) @@ -150,12 +132,12 @@ feeder.close() print "Pulled and imported %s packets from %s" % (fc.added, source_url) - def do_sync(self, local_url, other_url): + def do_sync(self, local_url, other_url, **kwargs): print "Exporting changes from monotone db to %s" % (local_url,) self.do_export(local_url) print "Synchronizing %s and %s" % (local_url, other_url) - local_md = MerkleDir(writeable_fs_for_url(local_url)) - other_md = MerkleDir(writeable_fs_for_url(other_url)) + local_md = MerkleDir(writeable_fs_for_url(local_url, **kwargs)) + other_md = MerkleDir(writeable_fs_for_url(other_url, **kwargs)) feeder = self.monotone.feeder(self.verbosity) pull_fc = Dumbtone.FeederCallback(feeder) push_c = Dumbtone.CounterCallback() ============================================================ --- fs.py 0741851af22991c3a1faf7345c8b85ab3b4c5a9f +++ fs.py d872e4820e299bb0b72296f54fdb54ee1725907b @@ -10,7 +10,7 @@ # This is necessary to properly parse sftp:// urls urlparse.uses_netloc.append("sftp") -def readable_fs_for_url(url): +def readable_fs_for_url(url, **kwargs): (scheme, host, path, query, frag) = urlparse.urlsplit(url, "file") if scheme == "file": assert not host @@ -20,18 +20,18 @@ return fs_read_httpftp.HTTPFTPReadableFS(url) elif scheme == "sftp": import fs_sftp - return fs_sftp.SFTPReadableFS(host, path) + return fs_sftp.SFTPReadableFS(host, path, **kwargs) else: raise BadURL, url -def writeable_fs_for_url(url): +def writeable_fs_for_url(url, **kwargs): (scheme, host, path, query, frag) = urlparse.urlsplit(url, "file") if scheme == "file": assert not host return LocalWriteableFs(path) elif scheme == "sftp": import fs_sftp - return fs_sftp.SFTPWriteableFS(host, path) + return fs_sftp.SFTPWriteableFS(host, path, **kwargs) else: raise BadURL, url ============================================================ --- fs_sftp.py c31b2800f0333335f2b4a9d6f8075563ad30bd1b +++ fs_sftp.py c298681baed4855de43c8668b88ce94a8b6cee73 @@ -8,10 +8,10 @@ # All of this heavily cribbed from demo{,_simple}.py in the paramiko # distribution, which is LGPL. -def load_host_keys(): +def load_host_keys(hostkeyfile): # this file won't exist on windows, but windows doesn't have a standard # location for this file anyway. - filename = os.path.expanduser('~/.ssh/known_hosts') + filename = os.path.expanduser(hostkeyfile) keys = {} try: f = open(filename, 'r') @@ -56,21 +56,38 @@ password = getpass.getpass("Password for address@hidden: " % (username, hostname)) return username, password, hostname, port -def get_host_key(hostname): - hkeys = load_host_keys() +def get_host_key(hostname, hostkeyfile): + hkeys = load_host_keys(hostkeyfile) if hkeys.has_key(hostname): return hkeys[hostname].values()[0] else: return None class SFTPReadableFS(fs.ReadableFS): - def __init__(self, hostspec, path): + def __init__(self, hostspec, path, **kwargs): self.dir = path username, password, hostname, port = get_user_password_host_port(hostspec) - hostkey = get_host_key(hostname) + + hostkeyfile = kwargs.get('hostfile','~/.ssh/known_hosts') + hostkey = get_host_key(hostname, hostkeyfile) + + key = None + if kwargs.has_key("dsskey"): + keypath=os.path.expanduser(kwargs["dsskey"]) + key = paramiko.DSSKey.from_private_key_file(keypath, + password=password) + elif kwargs.has_key("rsakey"): + keypath=os.path.expanduser(kwargs["rsakey"]) + key = paramiko.RSAKey.from_private_key_file(keypath, + password=password) + self.transport = paramiko.Transport((hostname, port)) - self.transport.connect(username=username, password=password, + if key: + self.transport.connect(username=username, pkey=key, hostkey=hostkey) + else: + self.transport.connect(username=username, password=password, + hostkey=hostkey) self.client = self.transport.open_sftp_client() def _fname(self, filename): ============================================================ --- monotone.py 2011146c9195c7156ab56b6e3f93d193b6b95a29 +++ monotone.py 875e49730a651ade4a72c6685e6dee84afe68ec1 @@ -1,7 +1,8 @@ import subprocess import threading import os.path import re +import zlib class MonotoneError (Exception): pass @@ -20,7 +21,7 @@ # this is technically broken; we might deadlock. # subprocess.Popen.communicate uses threads to do this; that'd be # better. - def write(self, data): + def _write(self, data): if self.process is None: self.process = subprocess.Popen(self.args, stdin=subprocess.PIPE, @@ -29,12 +30,27 @@ self.process.stdin.write(data) if self.verbosity>1: # processing every single call with a new process + # to give immediate error reporting stdout, stderr = self.process.communicate() print "writing: >>>",data,"<<<\n",stdout,stderr if self.process.returncode: raise MonotoneError, stderr self.process = None + # uncompresses and writes the data + def write(self, data): + # first, uncompress data + uncdata = zlib.decompress(data) + + if self.verbosity > 1: + # verbose op, splits the chunk in the individual packets, + # and reads them one by one + for pkt in uncdata.split("[end]"): + if len(pkt)>1: + self._write(pkt+"[end]") + else: + self._write(uncdata) + def close(self): if self.process is None: return