Added fn-copy command to copy from one repo URI to another.
diff --git a/infocalypse/__init__.py b/infocalypse/__init__.py
--- a/infocalypse/__init__.py
+++ b/infocalypse/__init__.py
@@ -121,7 +121,7 @@ import os
from mercurial import commands, util
from infcmds import get_config_info, execute_create, execute_pull, \
- execute_push, execute_setup
+ execute_push, execute_setup, execute_copy
def set_target_version(ui_, repo, opts, params, msg_fmt):
""" INTERNAL: Update TARGET_VERSION in params. """
@@ -151,6 +151,27 @@ def infocalypse_create(ui_, repo, **opts
params['INSERT_URI'] = insert_uri
execute_create(ui_, repo, params, stored_cfg)
+def infocalypse_copy(ui_, repo, **opts):
+ """ Copy an Infocalypse repository to a new URI. """
+ params, stored_cfg = get_config_info(ui_, opts)
+
+ insert_uri = opts['inserturi']
+ if insert_uri == '':
+ # REDFLAG: fix parameter definition so that it is required?
+ ui_.warn("Please set the insert URI with --inserturi.\n")
+ return
+
+ request_uri = opts['requesturi']
+ if request_uri == '':
+ request_uri = stored_cfg.get_request_uri(repo.root)
+ if not request_uri:
+ ui_.warn("There is no stored request URI for this repo.\n"
+ "Please set one with the --requesturi option.\n")
+ return
+ params['INSERT_URI'] = insert_uri
+ params['REQUEST_URI'] = request_uri
+ execute_copy(ui_, repo, params, stored_cfg)
+
def infocalypse_pull(ui_, repo, **opts):
""" Pull from an Infocalypse repository in Freenet.
"""
@@ -230,6 +251,11 @@ cmdtable = {
('r', 'rev', [],'maximum rev to push'),]
+ FCP_OPTS,
"[options]"),
+ "fn-copy": (infocalypse_copy,
+ [('', 'requesturi', '', 'request URI to copy from'),
+ ('', 'inserturi', '', 'insert URI to copy to'), ]
+ + FCP_OPTS,
+ "[options]"),
"fn-setup": (infocalypse_setup,
[('', 'tmpdir', '~/infocalypse_tmp', 'temp directory'),]
diff --git a/infocalypse/infcmds.py b/infocalypse/infcmds.py
--- a/infocalypse/infcmds.py
+++ b/infocalypse/infcmds.py
@@ -441,6 +441,32 @@ def execute_create(ui_, repo, params, st
finally:
cleanup(update_sm)
+# REDFLAG: LATER: make this work without a repo?
+def execute_copy(ui_, repo, params, stored_cfg):
+ """ Run the copy command. """
+ update_sm = None
+ try:
+ update_sm = setup(ui_, repo, params, stored_cfg)
+ handle_key_inversion(ui_, update_sm, params, stored_cfg)
+
+ ui_.status("%sInsert URI:\n%s\n" % (is_redundant(params['INSERT_URI']),
+ params['INSERT_URI']))
+ update_sm.start_copying(params['REQUEST_URI'],
+ params['INSERT_URI'])
+
+ run_until_quiescent(update_sm, params['POLL_SECS'])
+
+ if update_sm.get_state(QUIESCENT).arrived_from(((FINISHING,))):
+ ui_.status("Copied to:\n%s\n" %
+ '\n'.join(update_sm.get_state(INSERTING_URI).
+ get_request_uris()))
+ else:
+ ui_.status("Copy failed.\n")
+
+ handle_updating_config(repo, update_sm, params, stored_cfg)
+ finally:
+ cleanup(update_sm)
+
# REDFLAG: move into fcpclient?
#def usks_equal(usk_a, usk_b):
# assert is_usk(usk_a) and and is_usk(usk_b)
diff --git a/infocalypse/requestingbundles.py b/infocalypse/requestingbundles.py
--- a/infocalypse/requestingbundles.py
+++ b/infocalypse/requestingbundles.py
@@ -162,7 +162,7 @@ class RequestingBundles(RetryingRequestL
else:
self._handle_failure(client, msg, candidate)
- # Catch statemachine stalls.
+ # Catch state machine stalls.
if (self.parent.current_state == self and
self.is_stalled()):
self.parent.transition(self.failure_state)
diff --git a/infocalypse/updatesm.py b/infocalypse/updatesm.py
--- a/infocalypse/updatesm.py
+++ b/infocalypse/updatesm.py
@@ -454,6 +454,15 @@ class InsertingGraph(StaticRequestList):
StaticRequestList.reset(self)
self.working_graph = None
+ def get_top_key_tuple(self):
+ """ Get the python rep of the data required to insert a new URI
+ with the updated graph CHK(s). """
+ graph = self.parent.ctx.graph
+ assert not graph is None
+ return ((self.get_result(0)[1]['URI'],
+ self.get_result(1)[1]['URI']),
+ get_top_key_updates(graph))
+
def get_top_key_updates(graph):
""" Returns the update tuples needed to build the top key."""
@@ -499,16 +508,10 @@ class InsertingUri(StaticRequestList):
This creates the binary rep for the top level key
data and starts inserting it into Freenet.
"""
- require_state(from_state, INSERTING_GRAPH)
+ if not hasattr(from_state, 'get_top_key_tuple'):
+ raise Exception("Illegal Transition from: %s" % from_state.name)
- # Pull the graph CHKs out of the inserting
- # graph state instance. REDFLAG: Hardcoded state name ok?
- graph_insert = self.parent.get_state(INSERTING_GRAPH)
- graph = self.parent.ctx.graph
-
- top_key_tuple = ((graph_insert.get_result(0)[1]['URI'],
- graph_insert.get_result(1)[1]['URI']),
- get_top_key_updates(graph))
+ top_key_tuple = from_state.get_top_key_tuple()
salt = {0:0x00, 1:0xff} # grrr.... less code.
insert_uris = make_insert_uris(self.parent.ctx['INSERT_URI'])
@@ -716,6 +719,8 @@ class RequestingGraph(StaticRequestList)
StaticRequestList.__init__(self, parent, name, success_state,
failure_state)
+ # REDFLAG: remove this? why aren't I just calling get_top_key_tuple
+ # on REQUESTING_URI_4_INSERT???
def get_top_key_tuple(self):
""" Returns the Python rep of the data in the request uri. """
results = [candidate[5] for candidate in
@@ -791,6 +796,7 @@ FINISHING = 'FINISHING'
REQUESTING_URI = 'REQUESTING_URI'
REQUESTING_BUNDLES = 'REQUESTING_BUNDLES'
+REQUESTING_URI_4_COPY = 'REQUESTING_URI_4_COPY'
class UpdateStateMachine(RequestQueue, StateMachine):
""" A StateMachine implementaion to create, push to and pull from
@@ -844,6 +850,14 @@ class UpdateStateMachine(RequestQueue, S
FAILING),
FINISHING:CleaningUp(self, FINISHING, QUIESCENT),
+
+
+ # Copying.
+ # This doesn't verify that the graph chk(s) are fetchable.
+ REQUESTING_URI_4_COPY:RequestingUri(self, REQUESTING_URI_4_COPY,
+ INSERTING_URI,
+ FAILING),
+
}
self.current_state = self.get_state(QUIESCENT)
@@ -915,6 +929,22 @@ class UpdateStateMachine(RequestQueue, S
self.ctx['REQUEST_URI'] = request_uri
self.transition(REQUESTING_URI)
+
+ def start_copying(self, from_uri, to_insert_uri):
+ """ Start pulling changes from an Infocalypse repository URI
+ in Freenet into the local hg repository. """
+ self.require_state(QUIESCENT)
+ self.reset()
+ self.ctx.graph = None
+
+ assert not from_uri is None
+ assert not to_insert_uri is None
+
+ self.ctx['REQUEST_URI'] = from_uri
+ self.ctx['INSERT_URI'] = to_insert_uri
+ self.ctx['IS_KEYPAIR'] = False
+ self.transition(REQUESTING_URI_4_COPY)
+
# REDFLAG: SSK case untested
def start_inverting(self, insert_uri):
""" Start inverting a Freenet URI into it's analogous