infocalypse
 
(drak)
2013-08-07: merge operhiem1 into bab

merge operhiem1 into bab

diff --git a/infocalypse/__init__.py b/infocalypse/__init__.py
--- a/infocalypse/__init__.py
+++ b/infocalypse/__init__.py
@@ -568,7 +568,7 @@ extensions.wrapfunction(discovery, 'find
 # wrap the commands
 
 
-def freenetpathtouri(ui, path, pull=True):
+def freenetpathtouri(ui, path, repo=None, pull=True):
     """
     Return a usable request or insert URI. Expects a freenet:// or freenet:
     protocol to be specified.
@@ -588,9 +588,7 @@ def freenetpathtouri(ui, path, pull=True
     if not path.startswith("USK"):
         import wot
         if pull:
-            cfg = Config.from_ui(ui)
-            # TODO: Check for ID associated with this repo first.
-            truster = cfg.defaults['DEFAULT_TRUSTER']
+            truster = get_truster(ui, repo)
             return wot.resolve_pull_uri(ui, path, truster)
         else:
             return wot.resolve_push_uri(ui, path)
@@ -615,7 +613,7 @@ def freenetpull(orig, *args, **opts):
     # only act differently, if the target is an infocalypse repo.
     if not isfreenetpath(path):
         return orig(*args, **opts)
-    uri = freenetpathtouri(ui, path)
+    uri = freenetpathtouri(ui, path, repo)
     opts["uri"] = uri
     opts["aggressive"] = True # always search for the latest revision.
     return infocalypse_pull(ui, repo, **opts)
@@ -652,7 +650,7 @@ def freenetpush(orig, *args, **opts):
     # only act differently, if the target is an infocalypse repo.
     if not isfreenetpath(path):
         return orig(*args, **opts)
-    uri = parse_repo_path(freenetpathtouri(ui, path, pull=False))
+    uri = parse_repo_path(freenetpathtouri(ui, path, repo, pull=False))
     if uri is None:
         return
     # if the uri is the short form (USK@/name/#), generate the key and preprocess the uri.
@@ -703,6 +701,8 @@ def freenetclone(orig, *args, **opts):
             if dest.endswith(".R1") or dest.endswith(".R0"):
                 dest = dest[:-3]
 
+    # TODO: source holds the "repo" argument, but the naming is confusing in
+    # the context of freenetpathtouri().
     # check whether to create, pull or copy
     pulluri, pushuri = None, None
     if isfreenetpath(source):
diff --git a/infocalypse/commands.py b/infocalypse/commands.py
--- a/infocalypse/commands.py
+++ b/infocalypse/commands.py
@@ -89,8 +89,7 @@ def infocalypse_create(ui_, repo, **opts
         import fcp
         node = fcp.FCPNode()
         vcs_response =\
-            node.fcpPluginMessage(async=False,
-                                  plugin_name="plugins.WebOfTrust.WebOfTrust",
+            node.fcpPluginMessage(plugin_name="plugins.WebOfTrust.WebOfTrust",
                                   plugin_params=msg_params)[0]
 
         if vcs_response['header'] != 'FCPPluginReply' or\
@@ -197,7 +196,7 @@ def infocalypse_pull(ui_, repo, **opts):
         request_uri = get_uri_from_hash(ui_, repo, params, stored_cfg)
     elif opts['wot']:
         import wot
-        truster = get_truster(ui_, repo, opts)
+        truster = get_truster(ui_, repo, opts['truster'])
 
         request_uri = wot.resolve_pull_uri(ui_, opts['wot'], truster)
     elif opts['uri']:
@@ -223,7 +222,7 @@ def infocalypse_pull_request(ui, repo, *
                          "--wot.\n")
 
     wot_id, repo_name = opts['wot'].split('/', 1)
-    from_identity = get_truster(ui, repo, opts)
+    from_identity = get_truster(ui, repo, opts['truster'])
     to_identity = WoT_ID(wot_id, from_identity)
     wot.send_pull_request(ui, repo, from_identity, to_identity, repo_name)
 
@@ -510,23 +509,34 @@ def infocalypse_setupfreemail(ui, repo, 
     import wot
     # TODO: Here --truster doesn't make sense. There is no trust involved.
     # TODO: Should this be part of the normal fn-setup?
-    wot.execute_setup_freemail(ui, get_truster(ui, repo, opts))
+    wot.execute_setup_freemail(ui, get_truster(ui, repo, opts['truster']))
 
 
-def get_truster(ui, repo, opts):
+def get_truster(ui, repo=None, truster_identifier=None):
     """
-    Return a local WoT ID - either one that published this repository or the
-    default.
+    Return a local WoT ID.
+
+    Search for a local identity from most to least specific:
+    1. truster_identifier (if given)
+    2. identity that published this respository (if repo is given and an
+                                                 identity is set)
+    3. default truster
+
     :rtype : Local_WoT_ID
     """
     from wot_id import Local_WoT_ID
-    if opts['truster']:
-        return Local_WoT_ID(opts['truster'])
+    if truster_identifier:
+        return Local_WoT_ID(truster_identifier)
     else:
-        cfg = Config().from_ui(ui)
+        cfg = Config.from_ui(ui)
 
-        # Value is identity ID.
-        identity = cfg.get_wot_identity(cfg.get_request_uri(repo.root))
+        # Value is identity ID, so '@' prefix makes it an identifier with an
+        # empty nickname.
+        identity = None
+        if repo:
+            identity = cfg.get_wot_identity(cfg.get_request_uri(repo.root))
+
+        # Either repo is not given or there is no associated identity.
         if not identity:
             identity = cfg.defaults['DEFAULT_TRUSTER']
 
diff --git a/infocalypse/devnotes.txt b/infocalypse/devnotes.txt
--- a/infocalypse/devnotes.txt
+++ b/infocalypse/devnotes.txt
@@ -9,14 +9,8 @@ WoT identifier -
                  Web of Trust identifier. This is MyNickname@public-key-hash.
                  Often abbreviated "wot_id". Not to be confused with a WoT
                  identity.
-WoT identity -
+WoT identity ID -
               name given to the public key hash when returned by WoT.
-              Can also refer to a dictionary containing the Identity and
-              other attributes such as a request URI and contexts.
-
-              TODO: Apparently in the WoT code this is actually called
-              "identity ID". "ID" -> "identification" ~ "identifier",
-              right? What does that leave to call "nick@public key hash"?
 
 ------------------------------------------------------------
 Dev log:
diff --git a/infocalypse/wot_id.py b/infocalypse/wot_id.py
--- a/infocalypse/wot_id.py
+++ b/infocalypse/wot_id.py
@@ -107,6 +107,11 @@ class Local_WoT_ID(WoT_ID):
     """
 
     def __init__(self, wot_identifier):
+        """
+        Create a WoT_ID for a local identity matching the identifier.
+
+        :type wot_identifier: str
+        """
         id_num, message = _get_local_identity(wot_identifier)
 
         self.insert_uri = USK(message['Replies.InsertURI{0}'.format(id_num)])
@@ -120,6 +125,9 @@ def _get_identity(wot_identifier, truste
 
     Return an FCP reply from WoT for an identity on the truster's trust list
     matching the identifier. Abort if anything but exactly one match is found.
+
+    :type wot_identifier: str
+    :type truster: Local_WoT_ID
     """
     nickname_prefix, key_prefix = _parse_name(wot_identifier)
     # TODO: Support different FCP IP / port.
@@ -131,52 +139,52 @@ def _get_identity(wot_identifier, truste
     # TODO: Should this manually ensure an identity has a vcs context
     # otherwise?
 
-    # LCWoT can have * to allow a wildcard match, but a wildcard alone is
-    # not allowed. See Lucine Term Modifiers documentation. The nickname
-    # uses this syntax but the ID is inherently startswith().
-    params = {'Message': 'GetIdentitiesByPartialNickname',
-              'Truster': truster.identity_id,
-              'PartialNickname':
-              nickname_prefix + '*' if nickname_prefix else '',
-              'PartialID': key_prefix,
-              'MaxIdentities': 2,
-              'Context': 'vcs'}
+    # GetIdentitiesByPartialNickname does not support empty nicknames.
+    if nickname_prefix:
+        params = {'Message': 'GetIdentitiesByPartialNickname',
+                  'Truster': truster.identity_id,
+                  'PartialNickname':
+                  nickname_prefix + '*',
+                  'PartialID': key_prefix,
+                  'MaxIdentities': 2,
+                  'Context': 'vcs'}
 
-    response = \
-        node.fcpPluginMessage(async=False,
-                              plugin_name="plugins.WebOfTrust.WebOfTrust",
-                              plugin_params=params)[0]
+        response = \
+            node.fcpPluginMessage(plugin_name="plugins.WebOfTrust.WebOfTrust",
+                                  plugin_params=params)[0]
 
-    if response['header'] != 'FCPPluginReply' or \
-            'Replies.Message' not in response:
-        raise util.Abort('Unexpected reply. Got {0}\n'.format(response))
-    elif response['Replies.Message'] == 'Identities':
-        matches = response['Replies.IdentitiesMatched']
-        if matches == 0:
-            raise util.Abort("No identities match '{0}'\n".format(
-                wot_identifier))
-        elif matches == 1:
-            return response
-        else:
-            raise util.Abort("'{0}' is ambiguous.\n".format(wot_identifier))
+        if response['header'] != 'FCPPluginReply' or \
+                'Replies.Message' not in response:
+            raise util.Abort('Unexpected reply. Got {0}\n'.format(response))
+        elif response['Replies.Message'] == 'Identities':
+            matches = response['Replies.IdentitiesMatched']
+            if matches == 0:
+                raise util.Abort("No identities match '{0}'\n".format(
+                    wot_identifier))
+            elif matches == 1:
+                return response
+            else:
+                raise util.Abort("'{0}' matches more than one identity.\n"
+                                 .format(wot_identifier))
 
-    # Partial matching not supported, or unknown truster. The only
-    # difference in the errors is human-readable, so just try the exact
-    # match.
-    assert response['Replies.Message'] == 'Error'
+        # Partial matching not supported, or unknown truster. The only
+        # difference in the errors is human-readable, so try the exact match.
+        assert response['Replies.Message'] == 'Error'
 
     # key_prefix must be a complete key for the lookup to succeed.
     params = {'Message': 'GetIdentity',
-              'Truster': truster,
+              'Truster': truster.identity_id,
               'Identity': key_prefix}
     response = \
-        node.fcpPluginMessage(async=False,
-                              plugin_name="plugins.WebOfTrust.WebOfTrust",
+        node.fcpPluginMessage(plugin_name="plugins.WebOfTrust.WebOfTrust",
                               plugin_params=params)[0]
 
     if response['Replies.Message'] == 'Error':
         # Searching by exact public key hash, not matching.
-        raise util.Abort("No such identity '{0}'.\n".format(wot_identifier))
+        raise util.Abort("No identity has the complete public key hash '{0}'. "
+                         "({1}) To flexibly match by partial nickname and key "
+                         "use LCWoT for now.\n".format(key_prefix,
+                                                       wot_identifier))
 
     # There should be only one result.
     # Depends on https://bugs.freenetproject.org/view.php?id=5729
@@ -189,13 +197,14 @@ def _get_local_identity(wot_identifier):
 
     Return (id_number, FCP reply) from WoT for a local identity matching the
     identifier. Abort if anything but exactly one match is found.
+
+    :type wot_identifier: str
     """
     nickname_prefix, key_prefix = _parse_name(wot_identifier)
 
     node = fcp.FCPNode()
     response = \
-        node.fcpPluginMessage(async=False,
-                              plugin_name="plugins.WebOfTrust.WebOfTrust",
+        node.fcpPluginMessage(plugin_name="plugins.WebOfTrust.WebOfTrust",
                               plugin_params={'Message':
                                              'GetOwnIdentities'})[0]