This file is indexed.

/usr/share/pyshared/desktopcouch/application/start_local_couchdb.py is in python-desktopcouch-application 1.0.8-0ubuntu3.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# Copyright 2009 Canonical Ltd.
#
# This file is part of desktopcouch.
#
#  desktopcouch is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License version 3
# as published by the Free Software Foundation.
#
# desktopcouch is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with desktopcouch.  If not, see <http://www.gnu.org/licenses/>.
#
# Author: Stuart Langridge <stuart.langridge@canonical.com>
#         Eric Casteleijn <eric.casteleijn@canonical.com>

"""
Start local CouchDB server.
Steps:
    1. Work out which folders to use (running from source tree, or installed)
    2. Actually start CouchDB
    3. Check design documents in central folder against design documents in
       Couch, and overwrite any new ones
    4. Activate the pairing of ubuntu one by retrieving the oauth tokens using
       ubuntu sso.
    5. Write an HTML "bookmark" file which directs people to the local
       running CouchDB.

This script is normally called by advertisePort.py, which advertises the local
CouchDB port over D-Bus. That advertisePort script is started by D-Bus
activation.
"""

from __future__ import with_statement

import errno
import logging
import os
import re
import subprocess
import sys
import time

from desktopcouch.application import local_files
from desktopcouch.application.platform import (
    read_pidfile, process_is_couchdb, find_port)
import xdg.BaseDirectory


def run_couchdb(ctx=local_files.DEFAULT_CONTEXT):  # pylint: disable=R0912
    """Actually start the CouchDB process.  Return its PID."""
    pid = read_pidfile(ctx)
    if pid is not None and not process_is_couchdb(pid):
        print "Removing stale, deceptive pid file."
        os.remove(ctx.file_pid)
    local_exec = ctx.couch_exec_command + ['-b']
    try:
        # subprocess is buggy.  Chad patched, but that takes time to propagate.
        proc = subprocess.Popen(local_exec)
        while True:
            try:
                retcode = proc.wait()
                break
            except OSError, ex:
                if ex.errno == errno.EINTR:
                    continue
                raise
        if retcode < 0:
            print >> sys.stderr, "Child was terminated by signal", -retcode
        elif retcode > 0:
            print >> sys.stderr, "Child returned", retcode
    except OSError, ex:
        print >> sys.stderr, "Execution failed: %s: %s" % (ex, local_exec)
        exit(1)

    # give the process a chance to start
    pid = None
    for timeout in (0.4, 0.1, 0.1, 0.2, 0.5, 1, 3, 5):
        pid = read_pidfile(ctx=ctx)
        if pid is not None and process_is_couchdb(pid):
            break
        time.sleep(timeout)

    if pid is None:
        raise RuntimeError("Can not start couchdb.")

    # Loop for a number of times until the port has been found, this
    # has to be done because there's a slice of time between PID being written
    # and the listening port being active.
    port = None
    for timeout in (0.1, 0.1, 0.2, 0.5, 1, 3, 5, 8):
        try:
            port = find_port(pid=pid, ctx=ctx)
            # returns valid port, or raises exception
            break
        except RuntimeError:
            pass

        try:
            # Send no signal, merely test PID existence.
            os.kill(pid, 0)
        except OSError:
            raise RuntimeError("Couchdb PID%d exited.  Permissions?" % (pid,))

        time.sleep(timeout)

    if port is None:
        # Now we return valid port or raise exception.
        raise RuntimeError("Can not find port of couchdb.")

    ctx.sanitize_log_files()
    return pid, port


def update_bookmark_file(port, ctx=local_files.DEFAULT_CONTEXT):
    """Write out an HTML document that the user can bookmark to find
    their DB.

    """
    bookmark_file = os.path.join(ctx.db_dir, "couchdb.html")

    try:
        username, password = re.findall("<!-- !!([^!]+)!!([^!]+)!! -->", open(
            bookmark_file).read())[-1]
    except ValueError:
        raise IOError(
            "Bookmark file is corrupt.  Username/password are missing.")

    src_tmpl = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir,
                            "data", "couchdb.tmpl")
    if os.path.exists(src_tmpl):
        bookmark_template = src_tmpl
    else:
        for base in xdg.BaseDirectory.xdg_data_dirs:
            template_path = os.path.join(base, "desktopcouch", "couchdb.tmpl")
            if os.path.exists(template_path):
                bookmark_template = os.path.abspath(template_path)
                break
    fp = open(bookmark_template)
    html = fp.read()
    fp.close()

    fp = open(bookmark_file, "w")
    try:
        if port is not None:
            out = html.replace("[[COUCHDB_PORT]]", str(port))
            out = out.replace("[[COUCHDB_USERNAME]]", username)
            out = out.replace("[[COUCHDB_PASSWORD]]", password)
            fp.write(out)
            print "Browse your desktop CouchDB at file://%s" % \
                    os.path.realpath(bookmark_file)
    finally:
        fp.close()


def start_couchdb(ctx=local_files.DEFAULT_CONTEXT):
    """Execute each step to start a desktop CouchDB."""
    pid = None
    saved_exception = None
    for retry in range(10):
        try:
            pid, port = run_couchdb(ctx=ctx)
            break
        except RuntimeError, ex:
            saved_exception = ex
            logging.exception("Starting couchdb failed on try %d", retry)
            time.sleep(1)
            continue

    if pid is None:
        raise saved_exception           # pylint: disable=E0702

    # Note that we do not call update_design_documents and
    # update_pairing_service here. This is because
    # Couch won't actually have started yet, so when update_design_documents
    # calls the Records API, that will call back into get_port and we end up
    # starting Couch again. Instead, get_port calls update_design_documents
    # *after* Couch startup has occurred.
    update_bookmark_file(port, ctx=ctx)
    return pid


if __name__ == "__main__":
    start_couchdb()
    print "Desktop CouchDB started"