{"action":"created","comment":{"url":"https://api.github.com/repos/leapcode/soledad/pulls/comments/43771299","id":43771299,"diff_hunk":"@@ -0,0 +1,674 @@\n+# -*- coding: utf-8 -*-\n+# __init__.py\n+# Copyright (C) 2013 LEAP\n+#\n+# This program is free software: you can redistribute it and/or modify\n+# it under the terms of the GNU General Public License as published by\n+# the Free Software Foundation, either version 3 of the License, or\n+# (at your option) any later version.\n+#\n+# This program is distributed in the hope that it will be useful,\n+# but WITHOUT ANY WARRANTY; without even the implied warranty of\n+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n+# GNU General Public License for more details.\n+#\n+# You should have received a copy of the GNU General Public License\n+# along with this program. If not, see <http://www.gnu.org/licenses/>.\n+\n+\n+\"\"\"A U1DB backend that uses CouchDB as its persistence layer.\"\"\"\n+\n+\n+import json\n+import re\n+import uuid\n+import binascii\n+import time\n+\n+\n+from StringIO import StringIO\n+from urlparse import urljoin\n+from contextlib import contextmanager\n+from multiprocessing.pool import ThreadPool\n+\n+\n+from couchdb.client import Server, Database\n+from couchdb.multipart import MultipartWriter\n+from couchdb.http import (\n+    ResourceConflict,\n+    ResourceNotFound,\n+    ServerError,\n+    Session,\n+    urljoin as couch_urljoin,\n+    Resource,\n+)\n+from u1db.errors import (\n+    DatabaseDoesNotExist,\n+    InvalidGeneration,\n+    RevisionConflict,\n+)\n+from u1db.remote import http_app\n+\n+\n+from leap.soledad.common import ddocs\n+from .errors import raise_server_error\n+from .errors import raise_missing_design_doc_error\n+from leap.soledad.common.errors import InvalidURLError\n+from leap.soledad.common.document import ServerDocument\n+from leap.soledad.common.backend import SoledadBackend\n+\n+\n+COUCH_TIMEOUT = 120  # timeout for transfers between Soledad server and Couch\n+\n+\n+# monkey-patch the u1db http app to use ServerDocument\n+http_app.Document = ServerDocument\n+\n+\n+@contextmanager\n+def couch_server(url):\n+    \"\"\"\n+    Provide a connection to a couch server and cleanup after use.\n+\n+    For database creation and deletion we use an ephemeral connection to the\n+    couch server. That connection has to be properly closed, so we provide it\n+    as a context manager.\n+\n+    :param url: The URL of the Couch server.\n+    :type url: str\n+    \"\"\"\n+    session = Session(timeout=COUCH_TIMEOUT)\n+    server = Server(url=url, full_commit=False, session=session)\n+    yield server\n+\n+\n+THREAD_POOL = ThreadPool(20)\n+\n+\n+class CouchDatabase(object):\n+    \"\"\"\n+    Holds CouchDB related code.\n+    This class gives methods to encapsulate database operations and hide\n+    CouchDB details from backend code.\n+    \"\"\"\n+\n+    @classmethod\n+    def open_database(cls, url, create, ensure_ddocs=False, replica_uid=None):\n+        \"\"\"\n+        Open a U1DB database using CouchDB as backend.\n+\n+        :param url: the url of the database replica\n+        :type url: str\n+        :param create: should the replica be created if it does not exist?\n+        :type create: bool\n+        :param replica_uid: an optional unique replica identifier\n+        :type replica_uid: str\n+        :param ensure_ddocs: Ensure that the design docs exist on server.\n+        :type ensure_ddocs: bool\n+\n+        :return: the database instance\n+        :rtype: SoledadBackend\n+        \"\"\"\n+        # get database from url\n+        m = re.match('(^https?://[^/]+)/(.+)$', url)\n+        if not m:\n+            raise InvalidURLError\n+        url = m.group(1)\n+        dbname = m.group(2)\n+        with couch_server(url) as server:\n+            try:\n+                server[dbname]\n+            except ResourceNotFound:\n+                if not create:\n+                    raise DatabaseDoesNotExist()\n+                server.create(dbname)\n+        db = cls(url,\n+                 dbname, ensure_ddocs=ensure_ddocs)\n+        return SoledadBackend(\n+            db, replica_uid=replica_uid)\n+\n+    def __init__(self, url, dbname, ensure_ddocs=True):\n+        self._session = Session(timeout=COUCH_TIMEOUT)\n+        self._url = url\n+        self._dbname = dbname\n+        self._database = Database(\n+            urljoin(url, dbname),\n+            self._session)\n+        self._database.info()","path":"common/src/leap/soledad/common/couch/__init__.py","position":157,"original_position":137,"commit_id":"397343f890dbce9b3d6e9377b54c1f804d39479c","original_commit_id":"1218f5b61697ee56dd408a55df347ea0c1ad4001","user":{"login":"shyba","id":1302078,"avatar_url":"https://avatars.githubusercontent.com/u/1302078?v=3","gravatar_id":"","url":"https://api.github.com/users/shyba","html_url":"https://github.com/shyba","followers_url":"https://api.github.com/users/shyba/followers","following_url":"https://api.github.com/users/shyba/following{/other_user}","gists_url":"https://api.github.com/users/shyba/gists{/gist_id}","starred_url":"https://api.github.com/users/shyba/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shyba/subscriptions","organizations_url":"https://api.github.com/users/shyba/orgs","repos_url":"https://api.github.com/users/shyba/repos","events_url":"https://api.github.com/users/shyba/events{/privacy}","received_events_url":"https://api.github.com/users/shyba/received_events","type":"User","site_admin":false},"body":"This check happens on the line 123, but you are right. In fact, this line is a total a waste of time since the database will already blow if it doesn't exist on line 134, right before this info() call. Removing it...","created_at":"2015-11-03T16:36:49Z","updated_at":"2015-11-03T16:36:49Z","html_url":"https://github.com/leapcode/soledad/pull/281#discussion_r43771299","pull_request_url":"https://api.github.com/repos/leapcode/soledad/pulls/281","_links":{"self":{"href":"https://api.github.com/repos/leapcode/soledad/pulls/comments/43771299"},"html":{"href":"https://github.com/leapcode/soledad/pull/281#discussion_r43771299"},"pull_request":{"href":"https://api.github.com/repos/leapcode/soledad/pulls/281"}}},"pull_request":{"url":"https://api.github.com/repos/leapcode/soledad/pulls/281","id":46452357,"html_url":"https://github.com/leapcode/soledad/pull/281","diff_url":"https://github.com/leapcode/soledad/pull/281.diff","patch_url":"https://github.com/leapcode/soledad/pull/281.patch","issue_url":"https://api.github.com/repos/leapcode/soledad/issues/281","number":281,"state":"open","locked":false,"title":"Refactor/isolated couchdb code","user":{"login":"shyba","id":1302078,"avatar_url":"https://avatars.githubusercontent.com/u/1302078?v=3","gravatar_id":"","url":"https://api.github.com/users/shyba","html_url":"https://github.com/shyba","followers_url":"https://api.github.com/users/shyba/followers","following_url":"https://api.github.com/users/shyba/following{/other_user}","gists_url":"https://api.github.com/users/shyba/gists{/gist_id}","starred_url":"https://api.github.com/users/shyba/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shyba/subscriptions","organizations_url":"https://api.github.com/users/shyba/orgs","repos_url":"https://api.github.com/users/shyba/repos","events_url":"https://api.github.com/users/shyba/events{/privacy}","received_events_url":"https://api.github.com/users/shyba/received_events","type":"User","site_admin":false},"body":"Done\r\n-------\r\nGoals:\r\nMake all couchdb calls in a single place, isolating it from other backend code.\r\n\r\nNongoal:\r\nMove modules to right place, mocking for tests and other possible changes after this isolation. IMHO, those modifications should occur as needed after isolating couch code.","created_at":"2015-09-30T20:30:52Z","updated_at":"2015-11-03T16:36:49Z","closed_at":null,"merged_at":null,"merge_commit_sha":"90284a6ce12206dd15490ae578839f03abae281e","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/leapcode/soledad/pulls/281/commits","review_comments_url":"https://api.github.com/repos/leapcode/soledad/pulls/281/comments","review_comment_url":"https://api.github.com/repos/leapcode/soledad/pulls/comments{/number}","comments_url":"https://api.github.com/repos/leapcode/soledad/issues/281/comments","statuses_url":"https://api.github.com/repos/leapcode/soledad/statuses/397343f890dbce9b3d6e9377b54c1f804d39479c","head":{"label":"pixelated:refactor/isolated_couchdb_code","ref":"refactor/isolated_couchdb_code","sha":"397343f890dbce9b3d6e9377b54c1f804d39479c","user":{"login":"pixelated","id":8321323,"avatar_url":"https://avatars.githubusercontent.com/u/8321323?v=3","gravatar_id":"","url":"https://api.github.com/users/pixelated","html_url":"https://github.com/pixelated","followers_url":"https://api.github.com/users/pixelated/followers","following_url":"https://api.github.com/users/pixelated/following{/other_user}","gists_url":"https://api.github.com/users/pixelated/gists{/gist_id}","starred_url":"https://api.github.com/users/pixelated/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pixelated/subscriptions","organizations_url":"https://api.github.com/users/pixelated/orgs","repos_url":"https://api.github.com/users/pixelated/repos","events_url":"https://api.github.com/users/pixelated/events{/privacy}","received_events_url":"https://api.github.com/users/pixelated/received_events","type":"Organization","site_admin":false},"repo":{"id":39564686,"name":"soledad","full_name":"pixelated/soledad","owner":{"login":"pixelated","id":8321323,"avatar_url":"https://avatars.githubusercontent.com/u/8321323?v=3","gravatar_id":"","url":"https://api.github.com/users/pixelated","html_url":"https://github.com/pixelated","followers_url":"https://api.github.com/users/pixelated/followers","following_url":"https://api.github.com/users/pixelated/following{/other_user}","gists_url":"https://api.github.com/users/pixelated/gists{/gist_id}","starred_url":"https://api.github.com/users/pixelated/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pixelated/subscriptions","organizations_url":"https://api.github.com/users/pixelated/orgs","repos_url":"https://api.github.com/users/pixelated/repos","events_url":"https://api.github.com/users/pixelated/events{/privacy}","received_events_url":"https://api.github.com/users/pixelated/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/pixelated/soledad","description":"Synchronization Of Locally Encrypted Data Among Devices","fork":true,"url":"https://api.github.com/repos/pixelated/soledad","forks_url":"https://api.github.com/repos/pixelated/soledad/forks","keys_url":"https://api.github.com/repos/pixelated/soledad/keys{/key_id}","collaborators_url":"https://api.github.com/repos/pixelated/soledad/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/pixelated/soledad/teams","hooks_url":"https://api.github.com/repos/pixelated/soledad/hooks","issue_events_url":"https://api.github.com/repos/pixelated/soledad/issues/events{/number}","events_url":"https://api.github.com/repos/pixelated/soledad/events","assignees_url":"https://api.github.com/repos/pixelated/soledad/assignees{/user}","branches_url":"https://api.github.com/repos/pixelated/soledad/branches{/branch}","tags_url":"https://api.github.com/repos/pixelated/soledad/tags","blobs_url":"https://api.github.com/repos/pixelated/soledad/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/pixelated/soledad/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/pixelated/soledad/git/refs{/sha}","trees_url":"https://api.github.com/repos/pixelated/soledad/git/trees{/sha}","statuses_url":"https://api.github.com/repos/pixelated/soledad/statuses/{sha}","languages_url":"https://api.github.com/repos/pixelated/soledad/languages","stargazers_url":"https://api.github.com/repos/pixelated/soledad/stargazers","contributors_url":"https://api.github.com/repos/pixelated/soledad/contributors","subscribers_url":"https://api.github.com/repos/pixelated/soledad/subscribers","subscription_url":"https://api.github.com/repos/pixelated/soledad/subscription","commits_url":"https://api.github.com/repos/pixelated/soledad/commits{/sha}","git_commits_url":"https://api.github.com/repos/pixelated/soledad/git/commits{/sha}","comments_url":"https://api.github.com/repos/pixelated/soledad/comments{/number}","issue_comment_url":"https://api.github.com/repos/pixelated/soledad/issues/comments{/number}","contents_url":"https://api.github.com/repos/pixelated/soledad/contents/{+path}","compare_url":"https://api.github.com/repos/pixelated/soledad/compare/{base}...{head}","merges_url":"https://api.github.com/repos/pixelated/soledad/merges","archive_url":"https://api.github.com/repos/pixelated/soledad/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/pixelated/soledad/downloads","issues_url":"https://api.github.com/repos/pixelated/soledad/issues{/number}","pulls_url":"https://api.github.com/repos/pixelated/soledad/pulls{/number}","milestones_url":"https://api.github.com/repos/pixelated/soledad/milestones{/number}","notifications_url":"https://api.github.com/repos/pixelated/soledad/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/pixelated/soledad/labels{/name}","releases_url":"https://api.github.com/repos/pixelated/soledad/releases{/id}","created_at":"2015-07-23T11:55:37Z","updated_at":"2015-09-26T02:40:19Z","pushed_at":"2015-11-03T15:50:33Z","git_url":"git://github.com/pixelated/soledad.git","ssh_url":"git@github.com:pixelated/soledad.git","clone_url":"https://github.com/pixelated/soledad.git","svn_url":"https://github.com/pixelated/soledad","homepage":"https://leap.se/en/docs/soledad","size":3297,"stargazers_count":1,"watchers_count":1,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":1,"default_branch":"develop"}},"base":{"label":"leapcode:develop","ref":"develop","sha":"36f476c53f6f3532652d7428e306dcef1c37f879","user":{"login":"leapcode","id":1700464,"avatar_url":"https://avatars.githubusercontent.com/u/1700464?v=3","gravatar_id":"","url":"https://api.github.com/users/leapcode","html_url":"https://github.com/leapcode","followers_url":"https://api.github.com/users/leapcode/followers","following_url":"https://api.github.com/users/leapcode/following{/other_user}","gists_url":"https://api.github.com/users/leapcode/gists{/gist_id}","starred_url":"https://api.github.com/users/leapcode/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/leapcode/subscriptions","organizations_url":"https://api.github.com/users/leapcode/orgs","repos_url":"https://api.github.com/users/leapcode/repos","events_url":"https://api.github.com/users/leapcode/events{/privacy}","received_events_url":"https://api.github.com/users/leapcode/received_events","type":"Organization","site_admin":false},"repo":{"id":9917542,"name":"soledad","full_name":"leapcode/soledad","owner":{"login":"leapcode","id":1700464,"avatar_url":"https://avatars.githubusercontent.com/u/1700464?v=3","gravatar_id":"","url":"https://api.github.com/users/leapcode","html_url":"https://github.com/leapcode","followers_url":"https://api.github.com/users/leapcode/followers","following_url":"https://api.github.com/users/leapcode/following{/other_user}","gists_url":"https://api.github.com/users/leapcode/gists{/gist_id}","starred_url":"https://api.github.com/users/leapcode/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/leapcode/subscriptions","organizations_url":"https://api.github.com/users/leapcode/orgs","repos_url":"https://api.github.com/users/leapcode/repos","events_url":"https://api.github.com/users/leapcode/events{/privacy}","received_events_url":"https://api.github.com/users/leapcode/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/leapcode/soledad","description":"Synchronization Of Locally Encrypted Data Among Devices","fork":false,"url":"https://api.github.com/repos/leapcode/soledad","forks_url":"https://api.github.com/repos/leapcode/soledad/forks","keys_url":"https://api.github.com/repos/leapcode/soledad/keys{/key_id}","collaborators_url":"https://api.github.com/repos/leapcode/soledad/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/leapcode/soledad/teams","hooks_url":"https://api.github.com/repos/leapcode/soledad/hooks","issue_events_url":"https://api.github.com/repos/leapcode/soledad/issues/events{/number}","events_url":"https://api.github.com/repos/leapcode/soledad/events","assignees_url":"https://api.github.com/repos/leapcode/soledad/assignees{/user}","branches_url":"https://api.github.com/repos/leapcode/soledad/branches{/branch}","tags_url":"https://api.github.com/repos/leapcode/soledad/tags","blobs_url":"https://api.github.com/repos/leapcode/soledad/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/leapcode/soledad/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/leapcode/soledad/git/refs{/sha}","trees_url":"https://api.github.com/repos/leapcode/soledad/git/trees{/sha}","statuses_url":"https://api.github.com/repos/leapcode/soledad/statuses/{sha}","languages_url":"https://api.github.com/repos/leapcode/soledad/languages","stargazers_url":"https://api.github.com/repos/leapcode/soledad/stargazers","contributors_url":"https://api.github.com/repos/leapcode/soledad/contributors","subscribers_url":"https://api.github.com/repos/leapcode/soledad/subscribers","subscription_url":"https://api.github.com/repos/leapcode/soledad/subscription","commits_url":"https://api.github.com/repos/leapcode/soledad/commits{/sha}","git_commits_url":"https://api.github.com/repos/leapcode/soledad/git/commits{/sha}","comments_url":"https://api.github.com/repos/leapcode/soledad/comments{/number}","issue_comment_url":"https://api.github.com/repos/leapcode/soledad/issues/comments{/number}","contents_url":"https://api.github.com/repos/leapcode/soledad/contents/{+path}","compare_url":"https://api.github.com/repos/leapcode/soledad/compare/{base}...{head}","merges_url":"https://api.github.com/repos/leapcode/soledad/merges","archive_url":"https://api.github.com/repos/leapcode/soledad/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/leapcode/soledad/downloads","issues_url":"https://api.github.com/repos/leapcode/soledad/issues{/number}","pulls_url":"https://api.github.com/repos/leapcode/soledad/pulls{/number}","milestones_url":"https://api.github.com/repos/leapcode/soledad/milestones{/number}","notifications_url":"https://api.github.com/repos/leapcode/soledad/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/leapcode/soledad/labels{/name}","releases_url":"https://api.github.com/repos/leapcode/soledad/releases{/id}","created_at":"2013-05-07T17:30:44Z","updated_at":"2015-09-08T18:17:25Z","pushed_at":"2015-11-03T15:50:33Z","git_url":"git://github.com/leapcode/soledad.git","ssh_url":"git@github.com:leapcode/soledad.git","clone_url":"https://github.com/leapcode/soledad.git","svn_url":"https://github.com/leapcode/soledad","homepage":"https://leap.se/en/docs/design/soledad","size":5245,"stargazers_count":19,"watchers_count":19,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":20,"mirror_url":null,"open_issues_count":2,"forks":20,"open_issues":2,"watchers":19,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/leapcode/soledad/pulls/281"},"html":{"href":"https://github.com/leapcode/soledad/pull/281"},"issue":{"href":"https://api.github.com/repos/leapcode/soledad/issues/281"},"comments":{"href":"https://api.github.com/repos/leapcode/soledad/issues/281/comments"},"review_comments":{"href":"https://api.github.com/repos/leapcode/soledad/pulls/281/comments"},"review_comment":{"href":"https://api.github.com/repos/leapcode/soledad/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/leapcode/soledad/pulls/281/commits"},"statuses":{"href":"https://api.github.com/repos/leapcode/soledad/statuses/397343f890dbce9b3d6e9377b54c1f804d39479c"}}}}