infocalypse
 
(Steve Dougherty)
2013-07-28: Assume edition 0. Also R1 for push to freenet://

Assume edition 0. Also R1 for push to freenet:// Edition is easier to omit, and having Fred search for the latest edition is a reasonable default. When using internal commands (fn-*) the user is assumed to be more confident in Infocalypse internals. When using built-in commands with freenet: URIs, redundancy is less clear, so assuming redundancy seems helpful in use cases like hg clone . freenet:USK@.../repo_path. This also adds a warning when creating a repository on a path that does not specify redundancy. Assume edition: * fn-create --uri and --wot * fn-copy --inserturi and --requesturi * fn-reinsert --uri * fn-pull --uri * fn-push --uri * built-in command source Assume edition and redundancy: * built-in command destination

diff --git a/.bugs/bugs b/.bugs/bugs
--- a/.bugs/bugs
+++ b/.bugs/bugs
@@ -5,4 +5,5 @@ cloning from a freenet:// uri does not w
 set the timezone to UTC on cloning a freenet repo to avoid timezone-based attacks. | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:4dfc4cc28a7fa69f040776a7138da78ee89ec819, time:1355764180.36
 mime-type problems                                           | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:5916e6e8328e20d8b0276b76b7116dd432730778, time:1353463866.97
                                                              | owner:, open:False, id:65d8d544370f80538e325dae0b6c2da449c5bcfe, time:1373407147.03
+Add i18n support for messages.                               | owner:, open:True, id:7760991aef41c6d38be5315f742f6a6f350a0a76, time:1375010635.52
 simpler-wot-uris: name/repo                                  | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:d4f2df3ca2c441e4be389be846634f5a4a08906e, time:1372232568.9
diff --git a/.bugs/details/7760991aef41c6d38be5315f742f6a6f350a0a76.txt b/.bugs/details/7760991aef41c6d38be5315f742f6a6f350a0a76.txt
new file mode 100644
--- /dev/null
+++ b/.bugs/details/7760991aef41c6d38be5315f742f6a6f350a0a76.txt
@@ -0,0 +1,28 @@
+# Lines starting with '#' and sections without content
+# are not displayed by a call to 'details'
+#
+[paths]
+# Paths related to this bug.
+# suggested format: REPO_PATH:LINENUMBERS
+
+
+[details]
+# Additional details
+from mercurial.i18n import _
+raise util.Abort(_("destination " + dest + " already exists."))
+Does including a variable in the string allow translation still?
+
+[expected]
+# The expected result
+
+
+[actual]
+# What happened instead
+
+
+[reproduce]
+# Reproduction steps
+
+
+[comments]
+# Comments and updates - leave your name
diff --git a/infocalypse/__init__.py b/infocalypse/__init__.py
--- a/infocalypse/__init__.py
+++ b/infocalypse/__init__.py
@@ -590,6 +590,7 @@ def freenetpathtouri(ui, path, pull=True
         import wot
         if pull:
             cfg = Config.from_ui(ui)
+            # TODO: Check for ID associated with this repo first.
             truster = cfg.defaults['DEFAULT_TRUSTER']
             return wot.resolve_pull_uri(ui, path, truster)
         else:
@@ -706,10 +707,11 @@ def freenetclone(orig, *args, **opts):
     # check whether to create, pull or copy
     pulluri, pushuri = None, None
     if isfreenetpath(source):
-        pulluri = freenetpathtouri(ui, source)
+        pulluri = parse_repo_path(freenetpathtouri(ui, source))
 
     if isfreenetpath(dest):
-        pushuri = freenetpathtouri(ui, dest, pull=False)
+        pushuri = parse_repo_path(freenetpathtouri(ui, dest, pull=False),
+                                  assume_redundancy=True)
 
     # decide which infocalypse command to use.
     if pulluri and pushuri:
diff --git a/infocalypse/commands.py b/infocalypse/commands.py
--- a/infocalypse/commands.py
+++ b/infocalypse/commands.py
@@ -18,6 +18,8 @@ from validate import is_hex_string, is_f
 
 import os
 
+from keys import parse_repo_path
+
 
 def set_target_version(ui_, repo, opts, params, msg_fmt):
     """ INTERNAL: Update TARGET_VERSION in params. """
@@ -55,11 +57,15 @@ def infocalypse_create(ui_, repo, **opts
         ui_.warn("Please specify only one of --uri or --wot.\n")
         return
     elif opts['uri'] != '':
-        insert_uri = opts['uri']
+        insert_uri = parse_repo_path(opts['uri'])
     elif opts['wot'] != '':
-        # Expecting nick_prefix/repo_name.R<redundancy num>/edition
+        opts['wot'] = parse_repo_path(opts['wot'])
         nick_prefix, repo_name, repo_edition = opts['wot'].split('/', 2)
 
+        if not repo_name.endswith('.R1') and not repo_name.endswith('.R0'):
+            ui_.warning("Warning: Creating repository without redundancy. (R0"
+                        " or R1)")
+
         from wot_id import Local_WoT_ID
 
         ui_.status("Querying WoT for local identities.\n")
@@ -122,6 +128,8 @@ def infocalypse_copy(ui_, repo, **opts):
         # REDFLAG: fix parameter definition so that it is required?
         ui_.warn("Please set the insert URI with --inserturi.\n")
         return
+    else:
+        insert_uri = parse_repo_path(opts['inserturi'])
 
     request_uri = opts['requesturi']
     if request_uri == '':
@@ -130,6 +138,8 @@ def infocalypse_copy(ui_, repo, **opts):
             ui_.warn("There is no stored request URI for this repo.\n"
                      "Please set one with the --requesturi option.\n")
             return
+    else:
+        request_uri = parse_repo_path(opts['requesturi'])
 
     params['INSERT_URI'] = insert_uri
     params['REQUEST_URI'] = request_uri
@@ -147,6 +157,8 @@ def infocalypse_reinsert(ui_, repo, **op
             ui_.warn("There is no stored request URI for this repo.\n"
                      "Do a fn-pull from a repository USK and try again.\n")
             return
+    else:
+        request_uri = parse_repo_path(opts['uri'])
 
     level = opts['level']
     if level < 1 or level > 5:
@@ -174,6 +186,8 @@ def infocalypse_pull(ui_, repo, **opts):
      """
     params, stored_cfg = get_config_info(ui_, opts)
 
+    request_uri = ''
+
     if opts['hash']:
         # Use FMS to lookup the uri from the repo hash.
         if opts['uri'] != '':
@@ -188,8 +202,8 @@ def infocalypse_pull(ui_, repo, **opts):
         truster = get_truster(ui_, repo, opts)
 
         request_uri = wot.resolve_pull_uri(ui_, opts['wot'], truster)
-    else:
-        request_uri = opts['uri']
+    elif opts['uri']:
+        request_uri = parse_repo_path(opts['uri'])
 
     if request_uri == '':
         request_uri = stored_cfg.get_request_uri(repo.root)
@@ -241,6 +255,8 @@ def infocalypse_push(ui_, repo, **opts):
             ui_.warn("There is no stored insert URI for this repo.\n"
                      "Please set one with the --uri option.\n")
             return
+    else:
+        insert_uri = parse_repo_path(opts['uri'])
 
     set_target_version(ui_, repo, opts, params,
                        "Only pushing to version(s): %s\n")
diff --git a/infocalypse/keys.py b/infocalypse/keys.py
--- a/infocalypse/keys.py
+++ b/infocalypse/keys.py
@@ -1,4 +1,5 @@
 from string import split
+from mercurial import util
 
 
 class USK:
@@ -25,3 +26,50 @@ class USK:
 
     def __repr__(self):
         return "USK('%s')" % str(self)
+
+
+# Method instead of class because the existing code expects keys to be strings.
+# TODO: Would assuming edition / redundancy be better suited as arguments to
+# the USK __init__()? WoT paths are not USKs though. Once again RepoPath
+# might be nice. It would especially avoid repeated string operations to work
+# with redundancy level.
+def parse_repo_path(path, assume_redundancy=False):
+    """
+    Return the given path to a repo - either USK or WoT path -
+    assuming if unspecified:
+    * edition 0
+    * optionally, not by default (assume_redundancy) R1 redundancy
+
+    >>> parse_repo_path('USK@.../name')
+    'USK@.../name/0'
+    >>> parse_repo_path('USK@.../name/')
+    'USK@.../name/0'
+    >>> parse_repo_path('USK@.../name', assume_redundancy=True)
+    'USK@.../name.R1/0'
+    >>> parse_repo_path('USK@.../name.R0/5', assume_redundancy=True)
+    'USK@.../name.R0/5'
+    >>> parse_repo_path('not a key')
+    Traceback (most recent call last):
+        ...
+    Abort: Cannot parse 'not a key' as repository path.
+    """
+    parts = path.split('/')
+
+    if len(parts) == 2:
+        # Assuming USK@..,/name: '/edition' omitted.
+        parts.append('0')
+
+    if not len(parts) == 3:
+        raise util.Abort("Cannot parse '{0}' as repository path.".format(path))
+
+    if not parts[2]:
+        # Assuming USK@../name/: 'edition' omitted
+        parts[2] = '0'
+
+    if assume_redundancy:
+        # Assuming USK@.../repo_name/edition
+        repo_name = parts[1]
+        if not repo_name.endswith('.R1') and not repo_name.endswith('.R0'):
+            parts[1] += '.R1'
+
+    return '/'.join(parts)