infocalypse
 
(drak)
2013-08-07: merge more

merge more

diff --git a/.bugs/bugs b/.bugs/bugs
--- a/.bugs/bugs
+++ b/.bugs/bugs
@@ -1,9 +1,17 @@
 minimize dependencies                                        | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:0fc25f7b84f3e1fb89e9134a28eeabbe76bf054f, time:1372231529.45
+Problems using clone to create repositories.~                | owner:Steve Dougherty <steve@asksteved.com>, open:True, id:210c0e45adba5d500c6c5c00d750bfe43824cd3a, time:1375737210.02
 Add command to reinsert repo list.                           | owner:, open:False, id:2dcc27c850209062080906368530b4b9202271d0, time:1373407233.84
 pull fails, because config.get_wot_identity requests self.defaults['DEFAULT_TRUSTER'] which is not in defaults. | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:31beb672d404944a4655a546b21c95c7baa91002, time:1371735138.39
 cloning from a freenet:// uri does not work right now.       | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:35584408d800bb895d52dcf86cfba12c5b3237dd, time:1373100583.27
+Perform sanity check for multiple repos of the same name.    | owner:Steve Dougherty <steve@asksteved.com>, open:True, id:4160157833020b1a33d2e6b05dc12c848c891d03, time:1375733375.04
+Preserve non-Infocalypse repositories in the repository list. | owner:Steve Dougherty <steve@asksteved.com>, open:True, id:4d63383a07faa29083fb0b61846ab6cc3d3151be, time:1375733323.42
 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 --truster support to built-in commands.                  | owner:Steve Dougherty <steve@asksteved.com>, open:True, id:673a3103a58988552e0ef0b0ab20e8c75c9f6b1f, time:1375736861.8
 Add i18n support for messages.                               | owner:, open:True, id:7760991aef41c6d38be5315f742f6a6f350a0a76, time:1375010635.52
+Fix implied clone destination when cloning from freenet:.    | owner:Steve Dougherty <steve@asksteved.com>, open:True, id:9bd3ef617ba8871d28fbdae2500542e93302c791, time:1375736289.27
+Unit tests involving the node are hard.                      | owner:Steve Dougherty <steve@asksteved.com>, open:True, id:b01a53e59a2096254ecacdcee7673df5323d786e, time:1375737309.25
+Consider reworking repo list XML for conciseness.            | owner:Steve Dougherty <steve@asksteved.com>, open:True, id:b511106032c58ffe7b33d0eb65bac7ec5555575e, time:1375734587.66
 simpler-wot-uris: name/repo                                  | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:d4f2df3ca2c441e4be389be846634f5a4a08906e, time:1372232568.9
+Add a warning that comments and unrecognized entries in ~/.infocalypse are removed. | owner:Steve Dougherty <steve@asksteved.com>, open:True, id:e9236fdd23d44bfbf8565bb1a59317289f324fd6, time:1375735601.35
diff --git a/.bugs/details/210c0e45adba5d500c6c5c00d750bfe43824cd3a.txt b/.bugs/details/210c0e45adba5d500c6c5c00d750bfe43824cd3a.txt
new file mode 100644
--- /dev/null
+++ b/.bugs/details/210c0e45adba5d500c6c5c00d750bfe43824cd3a.txt
@@ -0,0 +1,27 @@
+# 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]
+When using clone . freenet:nickname/reponame to create a repository:
+    - The repository list is not updated. (No request URI in ~/.infocalypse)
+    - "hg push" doesn't work as the default path cannot be reversed to an insert URI and default-push is not set. Set default-push.
+
+[expected]
+# The expected result
+
+
+[actual]
+# What happened instead
+
+
+[reproduce]
+# Reproduction steps
+
+
+[comments]
+# Comments and updates - leave your name
diff --git a/.bugs/details/4160157833020b1a33d2e6b05dc12c848c891d03.txt b/.bugs/details/4160157833020b1a33d2e6b05dc12c848c891d03.txt
new file mode 100644
--- /dev/null
+++ b/.bugs/details/4160157833020b1a33d2e6b05dc12c848c891d03.txt
@@ -0,0 +1,31 @@
+# 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]
+Having multiple directories associated with the same request URI means a pull
+request cannot reasonably give a directory to pull to. (Or should it give all
+matches?)
+
+Having multiple repositories with the same name (in the request URI)
+makes pull requests not work (because it uses only name), and makes it more
+confusing to refer to repositories.
+
+[expected]
+# The expected result
+
+
+[actual]
+# What happened instead
+
+
+[reproduce]
+# Reproduction steps
+
+
+[comments]
+# Comments and updates - leave your name
diff --git a/.bugs/details/673a3103a58988552e0ef0b0ab20e8c75c9f6b1f.txt b/.bugs/details/673a3103a58988552e0ef0b0ab20e8c75c9f6b1f.txt
new file mode 100644
--- /dev/null
+++ b/.bugs/details/673a3103a58988552e0ef0b0ab20e8c75c9f6b1f.txt
@@ -0,0 +1,27 @@
+# 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]
+Currently built-in commands can only use the default truster or the one
+associated with that repository. This is likely sufficient, so this feature
+is low priority.
+
+[expected]
+# The expected result
+
+
+[actual]
+# What happened instead
+
+
+[reproduce]
+# Reproduction steps
+
+
+[comments]
+# Comments and updates - leave your name
diff --git a/.bugs/details/9bd3ef617ba8871d28fbdae2500542e93302c791.txt b/.bugs/details/9bd3ef617ba8871d28fbdae2500542e93302c791.txt
new file mode 100644
--- /dev/null
+++ b/.bugs/details/9bd3ef617ba8871d28fbdae2500542e93302c791.txt
@@ -0,0 +1,27 @@
+# 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]
+The implied destination of "hg clone freenet:operhiem1/pyProbe" is "freenet:operhiem1",
+which causes the URI parsing to fail because there's no repository name. In this
+case the destination should be the directory "pyProbe" instead.
+
+[expected]
+# The expected result
+
+
+[actual]
+# What happened instead
+
+
+[reproduce]
+# Reproduction steps
+
+
+[comments]
+# Comments and updates - leave your name
diff --git a/.bugs/details/b01a53e59a2096254ecacdcee7673df5323d786e.txt b/.bugs/details/b01a53e59a2096254ecacdcee7673df5323d786e.txt
new file mode 100644
--- /dev/null
+++ b/.bugs/details/b01a53e59a2096254ecacdcee7673df5323d786e.txt
@@ -0,0 +1,27 @@
+# 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]
+Investigate a mocking framework or something for better frontend tests.
+Currently there's just a very limited amount of backend testing, and tests
+that involve a node over FCP are not feasible.
+
+[expected]
+# The expected result
+
+
+[actual]
+# What happened instead
+
+
+[reproduce]
+# Reproduction steps
+
+
+[comments]
+# Comments and updates - leave your name
diff --git a/.bugs/details/b511106032c58ffe7b33d0eb65bac7ec5555575e.txt b/.bugs/details/b511106032c58ffe7b33d0eb65bac7ec5555575e.txt
new file mode 100644
--- /dev/null
+++ b/.bugs/details/b511106032c58ffe7b33d0eb65bac7ec5555575e.txt
@@ -0,0 +1,27 @@
+# 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]
+For instance, instead of a vcs field in each repository element, have all
+infocalypse repositories in a <infocalypse> element. Maybe also have them
+be <r> elements to be shorter.
+
+[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
@@ -568,12 +568,24 @@ extensions.wrapfunction(discovery, 'find
 # wrap the commands
 
 
-def freenetpathtouri(ui, path, repo=None, pull=True):
+def freenetpathtouri(ui, path, operation, repo=None):
     """
     Return a usable request or insert URI. Expects a freenet:// or freenet:
     protocol to be specified.
 
     If the key is not a USK it will be resolved as a WoT identity.
+
+
+    :param repo: Mercurial localrepository, used to resolve the truster set
+                 for the repository.
+    :param operation: A string name of the operation the URI will be used to
+                      perform. Used to return the appropriate result with
+                      WoT-integrated URI resolution. Valid operations are:
+                       * "pull" - request URI for existing repository.
+                       * "push" - insert URI for existing repository.
+                       * "clone-push" - insert URI for repository that might
+                                        not exist. (Skips looking up
+                                        published name and edition.)
     """
     # TODO: Is this the only URL encoding that may happen? Why not use a more
     # semantically meaningful function?
@@ -587,11 +599,16 @@ def freenetpathtouri(ui, path, repo=None
     # nick to be "USK", but this is a corner case. Using --wot will still work.
     if not path.startswith("USK"):
         import wot
-        if pull:
+        if operation == "pull":
             truster = get_truster(ui, repo)
             return wot.resolve_pull_uri(ui, path, truster)
+        elif operation == "push":
+            return wot.resolve_push_uri(ui, path)
+        elif operation == "clone-push":
+            return wot.resolve_push_uri(ui, path, resolve_edition=False)
         else:
-            return wot.resolve_push_uri(ui, path)
+            raise util.Abort("Internal error: invalid operation '{0}' when "
+                             "resolving WoT-integrated URI.".format(operation))
     else:
         return path
 
@@ -613,7 +630,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, repo)
+    uri = freenetpathtouri(ui, path, "pull", repo)
     opts["uri"] = uri
     opts["aggressive"] = True # always search for the latest revision.
     return infocalypse_pull(ui, repo, **opts)
@@ -650,7 +667,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, repo, pull=False))
+    uri = parse_repo_path(freenetpathtouri(ui, path, "push", repo))
     if uri is None:
         return
     # if the uri is the short form (USK@/name/#), generate the key and preprocess the uri.
@@ -706,10 +723,10 @@ def freenetclone(orig, *args, **opts):
     # check whether to create, pull or copy
     pulluri, pushuri = None, None
     if isfreenetpath(source):
-        pulluri = parse_repo_path(freenetpathtouri(ui, source))
+        pulluri = parse_repo_path(freenetpathtouri(ui, source, "pull"))
 
     if isfreenetpath(dest):
-        pushuri = parse_repo_path(freenetpathtouri(ui, dest, pull=False),
+        pushuri = parse_repo_path(freenetpathtouri(ui, dest, "clone-push"),
                                   assume_redundancy=True)
 
     # decide which infocalypse command to use.
diff --git a/infocalypse/wot.py b/infocalypse/wot.py
--- a/infocalypse/wot.py
+++ b/infocalypse/wot.py
@@ -14,7 +14,10 @@ from wot_id import Local_WoT_ID, WoT_ID
 FREEMAIL_SMTP_PORT = 4025
 FREEMAIL_IMAP_PORT = 4143
 VCS_TOKEN = "[vcs]"
-PLUGIN_NAME = "org.freenetproject.plugin.infocalypse_webui.main.InfocalypsePlugin"
+PLUGIN_NAME = "org.freenetproject.plugin.dvcs_webui.main.Plugin"
+# "infocalypse" is lower case in case it is used somewhere mixed case can
+# cause problems like a filesystem path. Used for machine-readable VCS name.
+VCS_NAME = "infocalypse"
 
 
 def connect(ui, repo):
@@ -87,7 +90,7 @@ def send_pull_request(ui, repo, from_ide
     to_address = require_freemail(to_identity)
 
     cfg = Config.from_ui(ui)
-    password = cfg.get_freemail_password(from_identity.identity_id)
+    password = cfg.get_freemail_password(from_identity)
 
     to_repo = find_repo(ui, to_identity, to_repo_name)
 
@@ -103,10 +106,8 @@ def send_pull_request(ui, repo, from_ide
     from_branch = repo_context.branch()
 
     # Use double-quoted scalars so that Unicode can be included. (Nicknames.)
-    # "infocalypse" is lower case in case it is used somewhere mixed case can
-    # cause problems like a filesystem path.
     footer = yaml.dump({'request': 'pull',
-                        'vcs': 'infocalypse',
+                        'vcs': VCS_NAME,
                         'source': from_uri + '#' + from_branch,
                         'target': to_repo}, default_style='"',
                        explicit_start=True, explicit_end=True,
@@ -245,9 +246,7 @@ def read_message_yaml(ui, from_address, 
                   " formatted. Details:\n%s\n" % (subject, e))
         return
 
-    # "infocalypse" is lower case in case it is used somewhere mixed case can
-    # cause problems like a filesystem path.
-    if request['vcs'] != 'infocalypse':
+    if request['vcs'] != VCS_NAME:
         ui.status("Notification '%s' is for '%s', not Infocalypse.\n"
                   % (subject, request['vcs']))
         return
@@ -300,7 +299,7 @@ def update_repo_listing(ui, for_identity
 
     for request_uri in build_repo_list(ui, for_identity):
         repo = ET.SubElement(root, 'repository', {
-            'vcs': 'Infocalypse',
+            'vcs': VCS_NAME,
         })
         repo.text = request_uri
 
@@ -386,7 +385,7 @@ def read_repo_listing(ui, identity):
     repositories = {}
     root = fromstring(repo_xml)
     for repository in root.iterfind('repository'):
-        if repository.get('vcs') == 'Infocalypse':
+        if repository.get('vcs') == VCS_NAME:
             uri = repository.text
             # Expecting key/reponame.R<num>/edition
             name = uri.split('/')[1].split('.')[0]
@@ -423,11 +422,16 @@ def resolve_pull_uri(ui, path, truster):
         return find_repo(ui, identity, repo_name)
 
 
-def resolve_push_uri(ui, path):
+def resolve_push_uri(ui, path, resolve_edition=True):
     """
     Return a push URI for the given path.
     Raise util.Abort if unable to resolve identity or repository.
 
+    :param resolve_edition: Defaults to True. If False, skips resolving the
+                            repository, uses the edition number 0. and does
+                            not modify the repository name. This is useful
+                            for finding a push URI for a repository that does
+                            not already exist.
     :param ui: For feedback.
     :param path: path describing a repo - nick@key/repo_name,
     where the identity is a local one. (Such that the insert URI is known.)
@@ -437,19 +441,25 @@ def resolve_push_uri(ui, path):
 
     local_id = Local_WoT_ID(wot_id)
 
-    insert_uri = local_id.insert_uri
+    if resolve_edition:
+        # TODO: find_repo should make it clearer that it returns a request URI,
+        # and return a USK.
+        repo = find_repo(ui, local_id, repo_name)
 
-    # TODO: find_repo should make it clearer that it returns a request URI,
-    # and return a USK.
-    repo = find_repo(ui, local_id, repo_name)
+        # Request URI
+        repo_uri = USK(repo)
 
-    # Request URI
-    repo_uri = USK(repo)
+        # Maintains name, edition.
+        repo_uri.key = local_id.insert_uri.key
 
-    # Maintains name, edition.
-    repo_uri.key = insert_uri.key
+        return str(repo_uri)
+    else:
+        repo_uri = local_id.insert_uri.clone()
 
-    return str(repo_uri)
+        repo_uri.name = repo_name
+        repo_uri.edition = 0
+
+        return str(repo_uri)
 
 
 def execute_setup_wot(ui_, local_id):