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