Author: saces Date: 2008-11-26 22:37:17 +0000 (Wed, 26 Nov 2008) New Revision: 23895
Modified: trunk/apps/pyFreenetHg/FreenetHg.py trunk/apps/pyFreenetHg/ReadMe.html Log: version 0.1: - major refactoring, its now a real "single file tool", no non-python-builtin dependencies - cleanup, remove redundant/obsolete functions Modified: trunk/apps/pyFreenetHg/FreenetHg.py =================================================================== --- trunk/apps/pyFreenetHg/FreenetHg.py 2008-11-26 18:05:32 UTC (rev 23894) +++ trunk/apps/pyFreenetHg/FreenetHg.py 2008-11-26 22:37:17 UTC (rev 23895) @@ -6,12 +6,12 @@ # To Public License, Version 2, as published by Sam Hocevar. See # http://sam.zoy.org/wtfpl/COPYING for more details. */ - import os, time import tempfile +import random +import socket import sys import dircache -import fcp from nntplib import NNTP from StringIO import StringIO @@ -19,9 +19,310 @@ from mercurial import hg from mercurial import commands -from mercurial import repo,cmdutil,util,ui,revlog,node +from mercurial import repo, cmdutil, util, ui, revlog, node from mercurial.node import bin +# +# fcp rape begin +# + +# the stuff below is treated as lib, so it should not refer to hg or other non-python-builtin stuff + +REQUIRED_NODE_VERSION=1183 +REQUIRED_EXT_VERSION=26 + +DEFAULT_FCP_HOST = "127.0.0.1" +DEFAULT_FCP_PORT = 9481 +DEFAULT_TIMEOUT = 300 + +# utils +def _getUniqueId(): + """Allocate a unique ID for a request""" + timenum = int( time.time() * 1000000 ); + randnum = random.randint( 0, timenum ); + return "id" + str( timenum + randnum ); + +# asynchronous stuff (single thread) +class FCPIOConnection(object): + """class for real i/o and format helpers""" + + def __init__(self, host, port, timeout): + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.socket.settimeout(timeout) + try: + self.socket.connect((host, port)) + except Exception, e: + raise Exception("Failed to connect to %s:%s - %s" % (host, port, e)) + pass + + def __del__(self): + """object is getting cleaned up, so disconnect""" + try: + self.socket.close() + except: + pass + + def _readline(self): + buf = [] + while True: + c = self.socket.recv(1) + if c == '\n': + break + buf.append(c) + ln = "".join(buf) + return ln + + def read(self, n): + chunks = [] + remaining = n + while remaining > 0: + chunk = self.socket.recv(remaining) + chunklen = len(chunk) + if chunk: + chunks.append(chunk) + else: + raise Exception("FCP socket closed by node") + remaining -= chunklen + buf = "".join(chunks) + print "testi: in:<"+str(len(buf))+" Bytes of data>" + return buf + + def readEndMessage(self): + #the first line is the message name + messagename = self._readline() + print "testi: in:"+messagename + items = {} + while True: + line = self._readline(); + print "testi: in:"+line + if (len(line.strip()) == 0): + continue # an empty line, jump over + + if line in ['End', 'EndMessage', 'Data']: + endmarker = line + break + + # normal 'key=val' pairs left + k, v = line.split("=", 1) + items[k] = v + + return FCPMessage(messagename, items, endmarker) + + def _sendLine(self, line): + print "testi: out:"+line + self.socket.sendall(line+"\n") + + def _sendMessage(self, messagename, hasdata=False, **kw): + self._sendLine(messagename) + for k, v in kw.items(): + line = k + "=" + str(v) + self._sendLine(line) + if kw.has_key("DataLength") or hasdata: + self._sendLine("Data") + else: + self._sendLine("EndMessage") + + def _sendCommand(self, messagename, hasdata, kw): + self._sendLine(messagename) + for k, v in kw.items(): + line = k + "=" + str(v) + self._sendLine(line) + if kw.has_key("DataLength") or hasdata: + self._sendLine("Data") + else: + self._sendLine("EndMessage") + + def _sendData(self, data): + print "testi: out:<"+str(len(data))+" Bytes of data>" + self.socket.sendall(data) + +class FCPConnection(FCPIOConnection): + """class for low level fcp protocol i/o""" + + def __init__(self, host, port, timeout): + """c'tor leaves a ready to use connection (hello done)""" + FCPIOConnection.__init__(self, host, port, timeout) + self._helo() + + def _helo(self): + """perform the initial FCP protocol handshake""" + name = _getUniqueId() + self._sendMessage("ClientHello", Name=name, ExpectedVersion="2.0") + msg = self.readEndMessage() + if not msg.isMessageName("NodeHello"): + raise Exception("Node helo failed: %s" % (msg.getMessageName())) + + # check versions + version = msg.getIntValue("Build") + if version < REQUIRED_NODE_VERSION: + raise Exception("Node to old. Found %d, but need %d" % (version, REQUIRED_NODE_VERSION)) + extversion = msg.getIntValue("ExtBuild") + if extversion < REQUIRED_EXT_VERSION: + raise Exception("Node-ext to old. Found %d, but need %d" % (extversion, REQUIRED_EXT_VERSION)) + + def sendCommand(self, command): + self._sendCommand(command.getCommandName(), command.hasData(), command.getItems()) + + def sendCommand(self, command, data): + self._sendCommand(command.getCommandName(), True, command.getItems()) + self._sendData(data) + + def write(self, data): + self._sendData(data) + +class FCPCommand(object): + """class for client to node messages""" + + _items = {} + + def __init__(self, name, identifier=None): + self._name = name + if None == identifier: + self._items['Identifier'] = _getUniqueId() + else: + self._items['Identifier'] = identifier + + def getCommandName(self): + return self._name; + + def getItems(self): + return self._items; + + def setItem(self, name, value): + self._items[name] = value; + + def hasData(self): + if self._items.has_key("DataLength"): + return True + else: + return False + +class FCPMessage(object): + """class for node to client messages""" + _items = {} + _messagename = "" + _endmarker = "" + + def __init__(self, messagename, items, endmarker): + self._messagename = messagename + self._endmarker = endmarker + self._items = items + + def isMessageName(self, testname): + if self._messagename in testname: + return True + else: + return False + + def getMessageName(self): + return self._messagename + + def getIntValue(self, name): + return int(self._items[name]) + + def getValue(self, name): + return self._items[name] + +# asynchronous stuff (thread save) +class FCPJob(object): + """abstract class for asynchronous jobs, they may use more then one fcp command and/or interact with the node in a complex manner""" + +class FCPSession(object): + """class for managing/running FCPJobs""" + +# the stuff above is treated as lib, so it should not refer to hg or other non-python-builtin stuff + +class HgFCPConnection(FCPConnection): + + def __init__(self, ui, **opts): + # defaults + host = DEFAULT_FCP_HOST + port = DEFAULT_FCP_PORT + timeout = DEFAULT_TIMEOUT + + host = ui.config('freenethg', 'fcphost') + port = ui.config('freenethg', 'fcpport') + + #host = opts.get('host', env.get("FCP_HOST", DEFAULT_FCP_HOST)) + #port = opts.get('port', env.get("FCP_PORT", DEFAULT_FCP_PORT)) + + # command line overwrites + if opts.get('fcphost'): + host = opts['fcphost'] + if opts.get('fcpport'): + port = opts['fcpport'] + if opts.get('fcptimeout'): + timeout = opts['fcptimeout'] + + FCPConnection.__init__(self, host, int(port), timeout) + +def hgBundlePut(connection, data): + + putcmd = FCPCommand('ClientPut') + putcmd.setItem('Verbosity', -1) + putcmd.setItem('URI', "CHK@") + putcmd.setItem('MaxRetries', -1) + putcmd.setItem('Metadata.ContentType', 'mercurial/bundle') + putcmd.setItem('DontCompress', 'false') + putcmd.setItem('PriorityClass', '1') + putcmd.setItem('UploadFrom', 'direct') + putcmd.setItem('DataLength', len(data)) + + connection.sendCommand(putcmd) + connection.write(data) + + while True: + msg = connection.readEndMessage() + + if msg.isMessageName('PutSuccessful'): + return msg.getValue('URI') + + if msg.isMessageName('ProtocolError'): + raise Exception("ProtocolError(%d) - %s: %s" % (msg.getIntValue('Code'), msg.getValue('CodeDescription'), msg.getValue('ExtraDescription'))) + + if msg.isMessageName('PutFailed'): + raise Exception("This should really not happen!") + + if msg.isMessageName('SimpleProgress'): + print "Succeeded: %d - Required: %d - Total: %d - Failed: %d - Final: %s" % (msg.getIntValue('Succeeded'), msg.getIntValue('Required'), msg.getIntValue('Total'), msg.getIntValue('FatallyFailed'), msg.getValue('FinalizedTotal')) + continue + + print msg.getMessageName() + +def hgBundleGet(connection, uri): + + getcmd = FCPCommand('ClientGet') + getcmd.setItem('Verbosity', -1) + getcmd.setItem('URI', uri) + getcmd.setItem('MaxRetries', 5) + getcmd.setItem('PriorityClass', '1') + getcmd.setItem('ReturnType', 'direct') + + connection.sendCommand(getcmd) + + while True: + msg = connection.readEndMessage() + + if msg.isMessageName('AllData'): + size = msg.getIntValue('DataLength'); + return connection.read(size) + + if msg.isMessageName('ProtocolError'): + raise Exception("ProtocolError(%d) - %s: %s" % (msg.getIntValue('Code'), msg.getValue('CodeDescription'), msg.getValue('ExtraDescription'))) + + if msg.isMessageName('GetFailed'): + raise Exception("This should really not happen!") + + if msg.isMessageName('SimpleProgress'): + print "Succeeded: %d - Required: %d - Total: %d - Failed: %d - Final: %s" % (msg.getIntValue('Succeeded'), msg.getIntValue('Required'), msg.getIntValue('Total'), msg.getIntValue('FatallyFailed'), msg.getValue('FinalizedTotal')) + continue + + print msg.getMessageName() + +# +# fcp rape end +# + class IndexPageMaker(object): """class for generate an index page""" @@ -89,8 +390,8 @@ subject_addon = None try: - f = open(template_path,'r') - subject_addon = f.readline().replace('\n','').replace('\r\n','') + f = open(template_path, 'r') + subject_addon = f.readline().replace('\n', '').replace('\r\n', '') user_template = f.read() f.close() except Exception, e: @@ -102,7 +403,7 @@ def post_updatestatic(self, notify_data, template_path=None): uri = notify_data['uri'] - uri = uri.endswith('/') and uri[:-1] or uri + uri = uri.endswith('/') and uri[: - 1] or uri repository_name = uri.split('/')[1] repository_version = uri.split('/')[2] @@ -126,7 +427,7 @@ template_data = {'body':body, 'subject':subject, 'fms_user':self.fms_user, - 'fms_groups':self.fms_groups,} + 'fms_groups':self.fms_groups, } article = StringIO(self.nntp_msg_template.substitute(template_data)) result = self.post(article) @@ -164,7 +465,7 @@ template_data = {'body':body, 'subject':subject, 'fms_user':self.fms_user, - 'fms_groups':self.fms_groups,} + 'fms_groups':self.fms_groups, } article = StringIO(self.nntp_msg_template.substitute(template_data)) result = self.post(article) @@ -185,21 +486,21 @@ def notify(self): uiw = self.ui.walkconfig() - trigger = self.ui.config('freenethg','notify') + trigger = self.ui.config('freenethg', 'notify') if trigger: for section, key, value in uiw: - if 'notify_' in section and key == 'type' and section.replace('notify_','') in trigger: + if 'notify_' in section and key == 'type' and section.replace('notify_', '') in trigger: m = getattr(self, value) m(section) def fmsnntp(self, config_section): - fms_host = self.ui.config(config_section,'fmshost') - fms_port = self.ui.config(config_section,'fmsport') - fms_user = self.ui.config(config_section,'fmsuser') - fms_groups = self.ui.config(config_section,'fmsgroups') - updatestatic_template_path = self.ui.config(config_section,'updatestatic_message_template') - bundle_template_path = self.ui.config(config_section,'bundle_message_template') + fms_host = self.ui.config(config_section, 'fmshost') + fms_port = self.ui.config(config_section, 'fmsport') + fms_user = self.ui.config(config_section, 'fmsuser') + fms_groups = self.ui.config(config_section, 'fmsgroups') + updatestatic_template_path = self.ui.config(config_section, 'updatestatic_message_template') + bundle_template_path = self.ui.config(config_section, 'bundle_message_template') if fms_host and fms_port and fms_user and fms_groups: print "Sending notification..." @@ -214,73 +515,20 @@ print "NNTP result: %s" % str(result) - - -class myFCP(fcp.FCPNode): - - def putraw(self, id, rawcmd, async=False): - """ - Inserts a raw command. - This is intended for testing and development, not for common use - - Arguments: - - id - job id, must be the same as identifier in raw command (if any) - - rawcmd - data passed as is to the node - - async - whether to do the job asynchronously, returning a job ticket - object (default False) - """ - - opts = {} - opts['async'] = async - opts['rawcmd'] = rawcmd - - return self._submitCmd(id, "", **opts) - - def putraw2(self, id, rawcmd): - """ - mine ;) verbosity hacking - do not print the command - """ - - self.verbosity = fcp.INFO - ticket = self.putraw(id, rawcmd, True) - ticket.waitTillReqSent() - self.verbosity = fcp.DETAIL - return ticket.wait() - - def put_static(self, id, rawcmd): - """putraw with status callback method""" - opts = dict() - opts['async'] = True - opts['rawcmd'] = rawcmd - opts['callback'] = self.put_status - - ticket = self._submitCmd(id, "", **opts) - ticket.wait() - return ticket.result - - def put_status(self, status, value): - """prints the status messages from jobticket""" - if status == 'pending' and value['header'] == 'SimpleProgress': - print "Succeeded: %d - Required: %d - Total: %d - Failed: %d - Final: %s" % (value['Succeeded'], value['Required'], value['Total'], value['FatallyFailed'], value['FinalizedTotal']) - if status == 'successful': - print "inserted successfully: %s" % value - - class _static_composer(object): """ a helper class to compose the ClientPutComplexDir """ #@ @+others #@+node:__init__ - def __init__(self, repo): + def __init__(self, repo, cmd): """ """ self._rootdir = repo.url()[5:] + '/.hg/' self._index = 0 self._fileitemlist = {} self._databuff = '' - self._cmdbuff = '' + self._cmd = cmd self._indexname = None a = dircache.listdir(self._rootdir) @@ -301,9 +549,9 @@ a = dircache.listdir(self._rootdir + dir) dircache.annotate(self._rootdir + dir, a) for s in a: - if s[-1:] == '/': - self._parseDir(dir + '/' + s[:-1]) - elif s[-4:] == 'lock': + if s[ - 1:] == '/': + self._parseDir(dir + '/' + s[: - 1]) + elif s[ - 4:] == 'lock': pass # called from hook, ignore else: self._addItem(dir, s) @@ -323,21 +571,21 @@ self._databuff = self._databuff + content idx = str(self._index) - self._cmdbuff = self._cmdbuff + "Files."+idx+".Name=.hg/" + virtname + '\n' - self._cmdbuff = self._cmdbuff + "Files."+idx+".UploadFrom=direct" + '\n' - self._cmdbuff = self._cmdbuff + "Files."+idx+".Metadata.ContentType=text/plain" + '\n' - self._cmdbuff = self._cmdbuff + "Files."+idx+".DataLength=" + str(len(content)) + '\n' + self._cmd.setItem("Files." + idx + ".Name", ".hg/" + virtname) + self._cmd.setItem("Files." + idx + ".UploadFrom", "direct") + self._cmd.setItem("Files." + idx + ".Metadata.ContentType", "text/plain") + self._cmd.setItem("Files." + idx + ".DataLength", str(len(content))) self._index = self._index + 1 def addIndex(self, indexpage): idx = str(self._index) - self._cmdbuff = self._cmdbuff + "Files."+idx+".Name=index.html"+'\n' - self._cmdbuff = self._cmdbuff + "Files."+idx+".UploadFrom=direct" + '\n' - self._cmdbuff = self._cmdbuff + "Files."+idx+".Metadata.ContentType=text/html" + '\n' - self._cmdbuff = self._cmdbuff + "Files."+idx+".DataLength=" + str(len(indexpage)) + '\n' + self._cmd.setItem("Files." + idx + ".Name", "index.html") + self._cmd.setItem("Files." + idx + ".UploadFrom", "direct") + self._cmd.setItem("Files." + idx + ".Metadata.ContentType", "text/html") + self._cmd.setItem("Files." + idx + ".DataLength", str(len(indexpage))) self._index = self._index + 1 - self._cmdbuff = self._cmdbuff + "DefaultName=index.html\n" + self._cmd.setItem("DefaultName", "index.html") self._databuff = self._databuff + indexpage @@ -346,6 +594,9 @@ def getRawCmd(self): return self._cmdbuff + "Data\n" + self._databuff + + def getData(self): + return self._databuff # every command must take a ui and and repo as arguments. # opts is a dict where you can find other command line flags @@ -354,17 +605,10 @@ # don't start with a dash. If no default value is given in the parameter list, # they are required def fcp_bundle(ui, repo, **opts): - # The doc string below will show up in hg help """write bundle to CHK/USK the bundel will be inserted as CHK@ if no uri is given see hg help bundle for bundle options """ - # setup fcp stuff - # set server, port - if not opts.get('fcphost'): - opts['fcphost'] = ui.config('freenethg', 'fcphost') - if not opts.get('fcpport'): - opts['fcpport'] = ui.config('freenethg', 'fcpport') # make tempfile tmpfd, tmpfname = tempfile.mkstemp('fcpbundle') @@ -382,55 +626,39 @@ #delete the tempfile again os.remove(tmpfname) - # now insert the data as chk (first step implementation) - #node = fcp.FCPNode(verbosity=fcp.DETAIL) - node = _make_node(**opts) - print "insert now. this may take a while..." + + try: + conn = HgFCPConnection(ui, **opts) + resulturi = hgBundlePut(conn, bundledata) + except Exception, e: + print e + return - insertresult = node.put(data=bundledata, priority=1, mimetype="mercurial/bundle", async=True, callback=node.put_status) - insertresult.wait() - - node.shutdown() - - if insertresult: - - notify_data = {'uri' : insertresult, + notify_data = {'uri' : resulturi, 'type' : 'bundle', - 'repository' : '%s' % repo.root.split('/')[-1], + 'repository' : '%s' % repo.root.split('/')[ - 1], 'base' : opts.get('base'), 'rev' : opts.get('rev')} - notifier = Notifier(ui, notify_data, autorun=True) + notifier = Notifier(ui, notify_data, autorun=True) - - def fcp_unbundle(ui, repo, uri , **opts): - # The doc string below will show up in hg help """unbundle from CHK/USK""" - # set server, port - if not opts.get('fcphost'): - opts['fcphost'] = ui.config('freenethg', 'fcphost') - if not opts.get('fcpport'): - opts['fcpport'] = ui.config('freenethg', 'fcpport') - # make tempfile tmpfd, tmpfname = tempfile.mkstemp('fcpbundle') - node = _make_node(**opts) - unbundle = None try: - unbundle = node.get(uri, priority=1, maxretries=5) - except fcp.node.FCPException, e: + conn = HgFCPConnection(ui, **opts) + unbundle = hgBundleGet(conn, uri) + except Exception, e: print e - node.shutdown() - if unbundle: - changes = unbundle[1] + changes = unbundle f = open(tmpfname, 'wb') f.write(changes) f.close() @@ -438,62 +666,6 @@ os.remove(tmpfname) -def _make_node(**opts): - fcpopts = {} - fcpopts['verbosity'] = fcp.INFO - host = opts.get('fcphost', None) - if host: - fcpopts['host'] = host - port = opts.get('fcpport', None) - if port: - fcpopts['port'] = port - #return node2.FCPNode(**fcpopts) - return myFCP(**fcpopts) - -def fcp_makestatic(ui, repo, uri=None, **opts): - """put the repo into freenet for access via static-http - """ - - id = "freenethgid" + str(int(time.time() * 1000000)) - - config_uri = ui.config('freenethg', 'inserturi') - - if uri == None: - if config_uri: - uri = config_uri - else: - uri="CHK@" - - if not opts.get('fcphost'): - opts['fcphost'] = ui.config('freenethg', 'fcphost') - if not opts.get('fcpport'): - opts['fcpport'] = ui.config('freenethg', 'fcpport') - cmd = "ClientPutComplexDir\n" + "URI=" + uri + "\nIdentifier=" + id - cmd = cmd + "\nVerbosity=-1\nPriorityClass=1\nMaxRetries=5\nDontCompress=true\n" - - composer = _static_composer(repo) - - print "Debug: " + cmd + composer.getCmd() - - print "site composer done." - print "insert now. this may take a while..." - - node = _make_node(**opts) - - testresult = None - - try: - #testresult = node.putraw(id, cmd + composer.getRawCmd()) - testresult = node.put_static(id, cmd + composer.getRawCmd()) - except fcp.node.FCPException, e: - print e - - node.shutdown() - -# if testresult: -# print "success: " + testresult - # here method for automated fms posts should be called - def fcp_createstatic(ui, repo, uri=None, **opts): """put the repo into freenet for access via static-http, updatedable (not implemented jet) """ @@ -501,56 +673,76 @@ pass def fcp_updatestatic(ui, repo, **opts): - """update the repo in freenet for access via static-http - """ + """update the repo in freenet for access via static-http""" updatestatic_hook(ui, repo, None, **opts) def updatestatic_hook(ui, repo, hooktype, node=None, source=None, **kwargs): """update static """ - id = "freenethgid" + str(int(time.time() * 1000000)) - host = ui.config('freenethg', 'fcphost') - port = ui.config('freenethg', 'fcpport') + + if not kwargs.get('fcphost'): + host = ui.config('freenethg', 'fcphost') + else: + host = kwargs.get('fcphost') + + if not kwargs.get('fcpport'): + port = ui.config('freenethg', 'fcpport') + else: + port = kwargs.get('fcpport') - uri = ui.config('freenethg', 'inserturi') + if not kwargs.get('uri'): + uri = ui.config('freenethg', 'inserturi') + else: + uri = kwargs.get('uri') - fcpopts = {} - fcpopts['verbosity'] = fcp.INFO - fcpopts['host'] = host - fcpopts['port'] = port - - #fcpopts['logfunc'] = ui.log - node = myFCP(**fcpopts) - - cmd = "ClientPutComplexDir\n" + "URI=" + uri + "\nIdentifier=" + id - cmd = cmd + "\nVerbosity=-1\nPriorityClass=1\nMaxRetries=5\nDontCompress=true\n" - - composer = _static_composer(repo) + cmd = FCPCommand("ClientPutComplexDir") + cmd.setItem('Verbosity', -1) + cmd.setItem('URI', uri) + cmd.setItem('MaxRetries', -1) + cmd.setItem('DontCompress', 'false') + cmd.setItem('PriorityClass', '1') + + composer = _static_composer(repo, cmd) page_maker = IndexPageMaker() indexpage = page_maker.get_index_page(ui) composer.addIndex(indexpage) - print "Debug: " + cmd + composer.getCmd() - print "site composer done." print "insert now. this may take a while..." result = None try: - result = node.put_static(id, cmd + composer.getRawCmd()) - except fcp.node.FCPException, e: - print e + conn = HgFCPConnection(ui, **kwargs) + conn.sendCommand(cmd, composer.getData()) + + while True: + msg = conn.readEndMessage() + + if msg.isMessageName('PutSuccessful'): + return msg.getValue('URI') + + if msg.isMessageName('ProtocolError'): + raise Exception("ProtocolError(%d) - %s: %s" % (msg.getIntValue('Code'), msg.getValue('CodeDescription'), msg.getValue('ExtraDescription'))) + + if msg.isMessageName('PutFailed'): + raise Exception("This should really not happen!") + + if msg.isMessageName('SimpleProgress'): + print "Succeeded: %d - Required: %d - Total: %d - Failed: %d - Final: %s" % (msg.getIntValue('Succeeded'), msg.getIntValue('Required'), msg.getIntValue('Total'), msg.getIntValue('FatallyFailed'), msg.getValue('FinalizedTotal')) + continue - node.shutdown() + print msg.getMessageName() + except Exception, e: + print e + return + if result: - notify_data = {'uri' : result, 'type' : 'updatestatic'} - notifier = Notifier(ui, notify_data, autorun=True) @@ -621,8 +813,9 @@ ] fcpopts = [ - ('', 'fcphost', None, 'specify fcphost if not 127.0.0.1'), - ('', 'fcpport', None, 'specify fcpport if not 9481'), + ('', 'fcphost', '', 'specify fcphost if not 127.0.0.1'), + ('', 'fcpport', 0, 'specify fcpport if not 9481'), + ('', 'fcptimeout', 0, 'specify fcp timeout if not 5 minutes'), ] cmdtable = { @@ -631,22 +824,16 @@ [('f', 'force', None, 'run even when remote repository is unrelated'), ('r', 'rev', [], 'a changeset you would like to bundle'), ('', 'base', [], 'a base changeset to specify instead of a destination'), + ('a', 'all', None, 'bundle all changesets in the repository'), ('', 'uri', None, 'use insert uri generate chk'), - ]+ remoteopts + fcpopts, + ] + remoteopts + fcpopts, 'hg fcp-bundle [--uri INSERTURI] [-f] [-r REV]... [--base REV]... [DEST]'), "fcp-unbundle": (fcp_unbundle, [('u', 'update', None, 'update to new tip if changesets were unbundled'), ] + fcpopts, 'hg fcp-unbundle [-u] FREENETKEY'), - "fcp-makestatic": (fcp_makestatic, - [('', 'uri', None, 'use insert uri instead generate chk') + "fcp-updatestatic": (fcp_updatestatic, + [('', 'uri', '', 'use insert uri instead from hgrc') ] + fcpopts, - 'hg fcp-makestatic [INSERTURI]'), - #"fcp-createstatic": (fcp_createstatic, - # [('a', 'auto', None, 'install update hook'), - # ] + fcpopts, - # 'hg fcp-createstatic'), - "fcp-updatestatic": (fcp_updatestatic, - [] + fcpopts, - 'hg fcp-updatestatic') + 'hg fcp-updatestatic [--uri INSERTURI]') } Modified: trunk/apps/pyFreenetHg/ReadMe.html =================================================================== --- trunk/apps/pyFreenetHg/ReadMe.html 2008-11-26 18:05:32 UTC (rev 23894) +++ trunk/apps/pyFreenetHg/ReadMe.html 2008-11-26 22:37:17 UTC (rev 23895) @@ -21,7 +21,6 @@ the basic idea: wrap around (selected) commands and use freenet as transport instead files hg fcp-bundle -> wraps around hg bundle and put a chk/usk instead a local file hg fcp-unbundle -> wraps around hg unbundle and get it from a chk/usk instead a local file - hg fcp-makestatic (not yet) -> create a site thats accessible via static-http://127.0.0.1:8888/freenetkey hg fcp-updatestatic -> do a commit hook upload, useful if the insert started from commit hook was failed hooks: @@ -35,7 +34,6 @@ <p> python >= 2.4<br> mercurial >= 1.x<br> -pyFCP<br> last not least: a running freenet node ;)<br /> optional: <a href="/USK at MYLAnId-ZEyXhDGGbYOa1gOtkZZrFNTXjFl1dibLj9E,Xpu27DoAKKc8b0718E-ZteFrGqCYROe7XBBJI57pB4M,AQACAAE/SiteToolPlugin/0/" target="_blank">SiteToolPlugin</a> </p>
