# # # add_file "README" # content [17d7783d5f2bc559a5a396006da5af2b867dcffc] # # add_file "plain.py" # content [cfd2cc32c5ff93036c13464236ef8923dcba8076] # # patch "dumb.py" # from [db3bcb120be2dc532f347c961ca6fa08bff72732] # to [b5170a6044e7a9859957db809628fea17e67ef94] # # patch "fs_read_httpftp.py" # from [4195f2926cfb7791501f7bb587cb9b672775263b] # to [33d9370b6c7787be5b31ef7859ab896ddaf3d24f] # # patch "monotone.py" # from [875e49730a651ade4a72c6685e6dee84afe68ec1] # to [68198897ddb64c93ded295f393d6e3f395ad82ba] # ============================================================ --- README 17d7783d5f2bc559a5a396006da5af2b867dcffc +++ README 17d7783d5f2bc559a5a396006da5af2b867dcffc @@ -0,0 +1,27 @@ +README for Monotone plain +========================= + +The monotone plain (or "dumb") protocol allows two-way synchronization via sftp or plain files, and one-way (pull) via http(s) and ftp. + +Prerequisites: + python 2.4 + the urlgrabber module (http://linux.duke.edu/projects/urlgrabber) + +Syntax: + + + + + + +NOTES: + +The monotone plain protocol always involves three entities: + a (local) monotone database + a local transit merkle-directory + a (possibly remote) merkle-directory to sync with +The sync directories are called merkle-directories because essentially contain a two-level merkle trie plus a datafile with the revision data. + +All synchronization is done between the two merkle-directories: the monotone database interacts only with the transit merkle-directory. + + ============================================================ --- plain.py cfd2cc32c5ff93036c13464236ef8923dcba8076 +++ plain.py cfd2cc32c5ff93036c13464236ef8923dcba8076 @@ -0,0 +1,73 @@ +""" +Simpler sync for monotone +""" +from optparse import OptionParser +from dumb import Dumbtone +import sys + +ACTIONS = [ "pull", "push", "sync"] + +def readConfig(cfgfile): + cfp = ConfigParser.SafeConfigParser() + cfp.addSection("default") + sfp.set("default","verbose","0") + sfp.set("default","hostKeys","~/.ssh/known_hosts") + cfp.read(cfgfile) + +def parseOpt(): + par = OptionParser(usage= +"""%prog [options] pull|push|sync remote-URL + + Pulls|Pushes|Synces with monotone plain instance at remote-URL" + Where remote-URL is: + + file:// + http[s]:// (pull only) + sftp://[user[:address@hidden:port] + When used with -dsskey or --rsakey the optional password argument + is used to decrypt the private key file. +""") + par.add_option("-d","--db", help="monotone db to use", metavar="STRING") + par.add_option("-l","--local", help="local transit directory", metavar="PATH") + par.add_option("--dsskey", + help="optional, sftp only. DSS private key file. Can't be specified with --rsakey", metavar="FILE") + par.add_option("--rsakey", + help="optional, sftp only. RSA private key file. Can't be specified with --dsskey", metavar="FILE") + par.add_option("--hostkey", default="~/.ssh/known_hosts", + help="sftp only. File containing host keys. On unices defaults to %default. Must be specified on Win32.", metavar="FILE") + par.add_option("-v", "--verbose", type="int", default=0, + help="verbosity level from 0 (normal) to 2 (debug)", metavar="NUM") + + (options, args) = par.parse_args() + if len(args)!=2 or args[0] not in ACTIONS: + par.print_help() + if not len(args): + sys.exit(1) + elif args[0] not in ACTIONS: + sys.exit("\nERROR: Invalid operation specified\n") + elif len(args)==1: + sys.exit("\nERROR: Missing remote-URL\n") + else: + sys.exit("\nERROR: Only one remote-URL allowed\n") + + if options.db is None: + sys.exit("\nERROR: monotone db not specified\n") + elif options.local is None: + sys.exit("\nERROR: local transit directory not specified\n") + return (options, args) + +if __name__ == "__main__": + (options, args) = parseOpt() + + optdict = {"dsskey":options.dsskey, + "rsakey":options.rsakey, + "hostkey":options.hostkey, + "verbose":options.verbose} + + mtn = Dumbtone(options.db, options.verbose) + if args[0]=="pull": + mtn.do_pull(options.local, args[1], **optdict) + elif args[0]=="push": + mtn.do_push(options.local, args[1], **optdict) + elif args[0]=="sync": + mtn.do_sync(options.local, args[1], **optdict) ============================================================ --- dumb.py db3bcb120be2dc532f347c961ca6fa08bff72732 +++ dumb.py b5170a6044e7a9859957db809628fea17e67ef94 @@ -145,10 +145,3 @@ feeder.close() print "Pulled and imported %s packets from %s" % (pull_fc.added, other_url) print "Pushed %s packets to %s" % (push_c.added, other_url) - -def main(name, args): - pass - -if __name__ == "__main__": - import sys - main(sys.argv[0], sys.argv[1:]) ============================================================ --- fs_read_httpftp.py 4195f2926cfb7791501f7bb587cb9b672775263b +++ fs_read_httpftp.py 33d9370b6c7787be5b31ef7859ab896ddaf3d24f @@ -10,18 +10,20 @@ assert self.url if self.url[-1] != "/": self.url += "/" + self.urlgrabber = urlgrabber.grabber.URLGrabber(keepalive=0, + proxies=None) def _url(self, filename): return urlparse.urljoin(self.url, filename) def open_read(self, filename): - return urlgrabber.urlopen(self._url(filename)) + return self.urlgrabber.urlopen(self._url(filename)) def fetch(self, filenames): files = {} for fn in filenames: try: - files[fn] = urlgrabber.urlread(self._url(fn)) + files[fn] = self.urlgrabber.urlread(self._url(fn)) except urlgrabber.grabber.URLGrabError: files[fn] = None return files @@ -31,5 +33,5 @@ for offset, length in bytes: # for HTTP, this is actually somewhat inefficient yield ((offset, length), - urlgrabber.urlread(url, range=(offset, offset+length))) + self.urlgrabber.urlread(url, range=(offset, offset+length))) ============================================================ --- monotone.py 875e49730a651ade4a72c6685e6dee84afe68ec1 +++ monotone.py 68198897ddb64c93ded295f393d6e3f395ad82ba @@ -13,7 +13,6 @@ # unless some packets are actually written (this is more efficient, # and also avoids spurious errors from monotone when 'read' doesn't # actually succeed in reading anything). - print "verbosity:",verbosity self.verbosity=verbosity self.args = args self.process = None