[tracker/sam/sandbox-rewrite-2] Rework the tracker-sandbox utility (again)



commit 9074a6f1e6a19b2a8433b4ce45c322fd03a14925
Author: Sam Thursfield <sam afuera me uk>
Date:   Tue Sep 10 17:13:30 2019 +0200

    Rework the tracker-sandbox utility (again)
    
    This fixes https://gitlab.gnome.org/GNOME/tracker/issues/111 and also
    simplifies the instructions in the README for running Tracker from
    the build tree.
    
    The sandbox utility is now executed from the top directory by running:
    
        python3 -m utils.trackertestutils
    
    Previously, due to importing stuff from trackertestutils. you needed to
    run it from the utils/ directory or set PYTHONPATH appropriately.
    
    Additionally, tracker-miners.git will ship a 'run-uninstalled' script
    to provide convenient access to the sandbox script and allow running
    Tracker from the build tree.

 README.md                              |  54 ++--
 tests/functional-tests/ipc/meson.build |   7 +-
 utils/sandbox/tracker-sandbox.py       | 334 ------------------------
 utils/trackertestutils/__main__.py     | 461 +++++++++++++++++++++++++++++++++
 utils/trackertestutils/dbusdaemon.py   | 107 ++------
 utils/trackertestutils/helpers.py      |   2 +-
 6 files changed, 520 insertions(+), 445 deletions(-)
---
diff --git a/README.md b/README.md
index c94639b87..c4c813e1f 100644
--- a/README.md
+++ b/README.md
@@ -84,51 +84,51 @@ At this point you can run the Tracker test suite from the `build` directory:
 
     meson test --print-errorlogs
 
-## Developing with tracker-sandbox
+## Using the run-uninstalled script
 
 Tracker normally runs automatically, indexing content in the background so that
 search results are available quickly when needed.
 
 When developing and testing Tracker you will normally want it to run in the
-foreground instead. The `tracker-sandbox` tool exists to help with this.
+foreground instead. You also probably want to run it from a build tree, rather
+than installing it somewhere everytime you make a change, and you certainly
+should isolates your development version from the real Tracker database in your
+home directory.
 
-You can run the tool directly from the tracker.git source tree. Ensure you are
-in the top of the tracker source tree and type this to see the --help output: 
+There is a tool to help with this, which is part of the 'trackertestutils'
+Python module.  You can run the tool using a helper script generated in the
+tracker-miners.git build process named 'run-uninstalled'.
 
-    ./utils/sandbox/tracker-sandbox.py --help
+Check the helper script is set up correctly by running this from your
+tracker-miners.git build tree:
 
-You should always pass the `--prefix` option, which should be the same as the
---prefix argument you passed to Meson. You may pass `--index` which to controls
-where Tracker's database is kept. You may also want to pass `--debug` to see
-detailed log output.
+    ./run-uninstalled --help
 
-The remaining arguments you pass to `tracker-sandbox` are shell commands which
-get run inside the sandbox. Use the `--` sentinel to ensure that the
-commandline arguments are processed correctly. First, let's see the status of
-the Tracker daemons:
+If run with no arguments, the script will start an interactive shell. Any
+arguments after a `--` sentinel are treated as a command to run in a non-interactive
+shell.
 
-    ./utils/sandbox/tracker-sandbox.py  --prefix ~/opt/tracker -- tracker daemon status
+So, let's see the status of the Tracker daemons. They should be all stopped
+right now.
 
-Let's try and index some content...
+    ./run-uninstalled -- tracker daemon status
 
-    ./utils/sandbox/tracker-sandbox.py  --prefix ~/opt/tracker -- tracker index ~/Music
+Let's try and index some content. (Subtitute ~/Music for any other location
+where you have interesting data). We need to explicitly tell the script to wait
+for the miners to finish, or it will exit too soon. (This is a workaround for
+[issue #122](https://gitlab.gnome.org/GNOME/tracker/issues/122).)
 
-... let's see what files were found ...
+    ./run-uninstalled --wait-for-miner=Files --wait-for-miner=Extract -- tracker index --file ~/Music
 
-    ./utils/sandbox/tracker-sandbox.py  --prefix ~/opt/tracker -- tracker sparql --list-files
+Let's see what files were found!
 
-... run a full-text search ...
+    ./run-uninstalled  --prefix ~/opt/tracker -- tracker sparql -q 'SELECT ?url { ?u nie:url ?url }
 
-    ./utils/sandbox/tracker-sandbox.py  --prefix ~/opt/tracker -- tracker search "bananas"
+Or, you can try a full-text search ...
 
-... or run a SPARQL query on the content:
+    ./run-uninstalled -- tracker search "bananas"
 
-    ./utils/sandbox/tracker-sandbox.py  --prefix ~/opt/tracker -- tracker sparql
-        --query "SELECT ?url { ?resource a nfo:FileDataObject ; nie:url ?url . }"
-
-If you run `tracker-sandbox` without a command argument, it will open an
-interactive shell inside the sandbox. From here you can use debugging tools
-such as GDB.
+There are many more things you can do with the script.
 
 For more information about developing Tracker, look at
 https://wiki.gnome.org/Projects/Tracker and HACKING.md.
diff --git a/tests/functional-tests/ipc/meson.build b/tests/functional-tests/ipc/meson.build
index 1c558c514..a0548b1c9 100644
--- a/tests/functional-tests/ipc/meson.build
+++ b/tests/functional-tests/ipc/meson.build
@@ -3,8 +3,7 @@ functional_ipc_test_c_args = [
   '-DTEST_ONTOLOGIES_DIR="@0@"'.format(tracker_uninstalled_nepomuk_ontologies_dir),
 ]
 
-tracker_sandbox = find_program(join_paths(source_root, 'utils', 'sandbox', 'tracker-sandbox.py'))
-sandbox_args = ['--dbus-config', test_dbus_config, '--debug-sandbox', '--index-tmpdir', '--']
+sandbox_args = ['-m', 'trackertestutils', '--dbus-config', test_dbus_config, '--debug-sandbox', 
'--index-tmpdir', '--']
 
 sandbox_env = environment()
 
@@ -16,7 +15,7 @@ test_env.set('TRACKER_TEST_DOMAIN_ONTOLOGY_RULE', tracker_uninstalled_domain_rul
 insert_or_replace_test = executable('test-insert-or-replace',
   'test-insert-or-replace.vala', tracker_sparql_vapi,
   dependencies: [tracker_common_dep, tracker_sparql_dep])
-test('functional-ipc-insert-or-replace', tracker_sandbox,
+test('functional-ipc-insert-or-replace', python,
   args: sandbox_args + [insert_or_replace_test],
   env: test_env)
 
@@ -25,6 +24,6 @@ bus_query_cancellation_test = executable('test-bus-query-cancellation',
   c_args: functional_ipc_test_c_args,
   dependencies: [tracker_common_dep, tracker_sparql_dep])
 
-test('functional-ipc-bus-query-cancellation', tracker_sandbox,
+test('functional-ipc-bus-query-cancellation', python,
   args: sandbox_args + [bus_query_cancellation_test],
   env: test_env)
diff --git a/utils/trackertestutils/__main__.py b/utils/trackertestutils/__main__.py
new file mode 100644
index 000000000..859a82545
--- /dev/null
+++ b/utils/trackertestutils/__main__.py
@@ -0,0 +1,461 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2012-2013 Martyn Russell <martyn lanedo com>
+# Copyright (C) 2012      Sam Thursfield <sam thursfield codethink co uk>
+# Copyright (C) 2016,2019 Sam Thursfield <sam afuera me uk>
+#
+# This is a tool for running development versions of Tracker.
+#
+# See README.md for usage information.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+import argparse
+import collections
+import configparser
+import locale
+import logging
+import os
+import shlex
+import shutil
+import signal
+import subprocess
+import sys
+import tempfile
+import time
+
+from gi.repository import Gio
+from gi.repository import GLib
+
+from . import dbusdaemon
+from . import helpers
+from . import mainloop
+
+# Script
+script_name = 'tracker-sandbox'
+script_about = "Tracker Sandbox developer tool."
+
+default_index_location = '/tmp/tracker-sandbox'
+
+store_pid = -1
+store_proc = None
+
+original_xdg_data_home = GLib.get_user_data_dir()
+
+# Template config file
+config_template = """
+[General]
+verbosity=0
+sched-idle=0
+initial-sleep=0
+
+[Monitors]
+enable-monitors=false
+
+[Indexing]
+throttle=0
+index-on-battery=true
+index-on-battery-first-time=true
+index-removable-media=false
+index-optical-discs=false
+low-disk-space-limit=-1
+index-recursive-directories=;
+index-single-directories=;
+ignored-directories=;
+ignored-directories-with-content=;
+ignored-files=
+crawling-interval=-1
+removable-days-threshold=3
+
+[Writeback]
+enable-writeback=false
+"""
+
+
+log = logging.getLogger('sandbox')
+
+
+# Environment / Clean up
+
+def environment_unset(dbus):
+    log.debug('Cleaning up processes ...')
+
+    dbus.stop()
+
+    # FIXME: clean up tracker-store, can't use 'tracker daemon ...' for this,
+    #        that kills everything it finds in /proc sadly.
+    if store_pid > 0:
+        log.debug('  Killing Tracker store')
+        os.kill(store_pid, signal.SIGTERM)
+
+
+def environment_set_and_add_path(env, var, prefix, suffix):
+    new = os.path.join(prefix, suffix)
+
+    if var in env:
+        existing = env[var]
+        full = '%s:%s' % (new, existing)
+    else:
+        full = new
+
+    env[var] = full
+
+
+def create_sandbox(index_location, prefix=None, verbosity=0, dbus_config=None):
+    assert prefix is None or dbus_config is None
+
+    extra_env = {}
+
+    # Data
+    extra_env['XDG_DATA_HOME'] = '%s/data/' % index_location
+    extra_env['XDG_CONFIG_HOME'] = '%s/config/' % index_location
+    extra_env['XDG_CACHE_HOME'] = '%s/cache/' % index_location
+    extra_env['XDG_RUNTIME_DIR'] = '%s/run/' % index_location
+
+    # Prefix - only set if non-standard
+    if prefix and prefix != '/usr':
+        environment_set_and_add_path(extra_env, 'PATH', prefix, 'bin')
+        environment_set_and_add_path(extra_env, 'LD_LIBRARY_PATH', prefix, 'lib')
+        environment_set_and_add_path(extra_env, 'XDG_DATA_DIRS', prefix, 'share')
+
+    # Preferences
+    extra_env['TRACKER_USE_CONFIG_FILES'] = 'yes'
+
+    extra_env['G_MESSAGES_PREFIXED'] = 'all'
+
+    extra_env['TRACKER_VERBOSITY'] = str(verbosity)
+
+    log.debug('Using prefix location "%s"' % prefix)
+    log.debug('Using index location "%s"' % index_location)
+
+    sandbox = helpers.TrackerDBusSandbox(dbus_config, extra_env=extra_env)
+    sandbox.start()
+
+    # Update our own environment, so when we launch a subprocess it has the
+    # same settings as the Tracker daemons.
+    os.environ.update(extra_env)
+    os.environ['DBUS_SESSION_BUS_ADDRESS'] = sandbox.daemon.get_address()
+    os.environ['TRACKER_SANDBOX'] = '1'
+
+    return sandbox
+
+
+def config_set(content_locations_recursive=None, content_locations_single=None):
+    # Make sure File System miner is configured correctly
+    config_dir = os.path.join(os.environ['XDG_CONFIG_HOME'], 'tracker')
+    config_filename = os.path.join(config_dir, 'tracker-miner-fs.cfg')
+
+    log.debug('Using config file "%s"' % config_filename)
+
+    # Only update config if we're updating the database
+    os.makedirs(config_dir, exist_ok=True)
+
+    if not os.path.exists(config_filename):
+        f = open(config_filename, 'w')
+        f.write(config_template)
+        f.close()
+
+        log.debug('  Miner config file written')
+
+    # Set content path
+    config = configparser.ConfigParser()
+    config.optionxform = str
+    config.read(config_filename)
+
+    if content_locations_recursive:
+        log.debug("Using content locations: %s" %
+              content_locations_recursive)
+    if content_locations_single:
+        log.debug("Using non-recursive content locations: %s" %
+              content_locations_single)
+
+    def locations_gsetting(locations):
+        locations = [dir if dir.startswith('&') else os.path.abspath(dir)
+                     for dir in locations]
+        return GLib.Variant('as', locations).print_(False)
+
+    if not config.has_section('General'):
+        config.add_section('General')
+
+    config.set('General', 'index-recursive-directories',
+               locations_gsetting(content_locations_recursive or []))
+    config.set('General', 'index-single-directories',
+               locations_gsetting(content_locations_single or []))
+
+    with open(config_filename, 'w') as f:
+        config.write(f)
+
+
+def link_to_mime_data():
+    '''Create symlink to $XDG_DATA_HOME/mime in our custom data home dir.
+
+    Mimetype detection seems to break horribly if the $XDG_DATA_HOME/mime
+    directory is missing. Since we have to override the normal XDG_DATA_HOME
+    path, we need to work around this by linking back to the real mime data.
+
+    '''
+    new_xdg_data_home = os.environ['XDG_DATA_HOME']
+    old_mime_dir = os.path.join(original_xdg_data_home, 'mime')
+    if os.path.exists(old_mime_dir):
+        new_mime_dir = os.path.join(new_xdg_data_home, 'mime')
+        if (not os.path.exists(new_mime_dir)
+                and not os.path.islink(new_mime_dir)):
+            os.makedirs(new_xdg_data_home, exist_ok=True)
+            os.symlink(
+                os.path.join(original_xdg_data_home, 'mime'), new_mime_dir)
+
+
+def argument_parser():
+    class expand_path(argparse.Action):
+        """Expand user- and relative-paths in filenames."""
+        # From https://gist.github.com/brantfaircloth/1443543
+        def __call__(self, parser, namespace, values, option_string=None):
+            setattr(namespace, self.dest, os.path.abspath(os.path.expanduser(values)))
+
+    parser = argparse.ArgumentParser(description=script_about)
+    parser.add_argument('--dbus-config', metavar='FILE', action=expand_path,
+                        help="use a custom D-Bus config file to locate the "
+                             "Tracker daemons. This can be used to run Tracker "
+                             "from a build tree of tracker-miners.git, by "
+                             "using the generated file ./tests/test-bus.conf")
+    parser.add_argument('-p', '--prefix', metavar='DIR', action=expand_path,
+                        help="run Tracker from the given install prefix. You "
+                             "can run the system version of Tracker by "
+                             "specifying --prefix=/usr")
+    parser.add_argument('-v', '--verbosity', default=None,
+                        choices=['0', '1', '2', '3', 'errors', 'minimal', 'detailed', 'debug'],
+                        help="show debugging info from Tracker processes")
+    parser.add_argument('-i', '--index', metavar='DIR', action=expand_path,
+                        default=default_index_location, dest='index_location',
+                        help=f"directory to the index (default={default_index_location})")
+    parser.add_argument('--index-tmpdir', action='store_true',
+                        help="create index in a temporary directory and "
+                             "delete it on exit (useful for automated testing)")
+    parser.add_argument('--wait-for-miner', type=str, action='append',
+                        help="wait for one or more daemons to start, and "
+                             "return to idle for at least 1 second, before "
+                             "exiting. Usually used with `tracker index` where "
+                             "you should pass --wait-for-miner=Files and "
+                             "--wait-for-miner=Extract")
+    parser.add_argument('--debug-dbus', action='store_true',
+                        help="show stdout and stderr messages from every daemon "
+                             "running on the sandbox session bus. By default we "
+                             "only show messages logged by Tracker daemons.")
+    parser.add_argument('--debug-sandbox', action='store_true',
+                        help="show debugging info from tracker-sandbox")
+    parser.add_argument('command', type=str, nargs='*', help="Command to run inside the shell")
+
+    return parser
+
+
+def verbosity_as_int(verbosity):
+    verbosity_map = {
+        'errors': 0,
+        'minimal': 1,
+        'detailed': 2,
+        'debug': 3
+    }
+    return verbosity_map.get(verbosity, int(verbosity))
+
+
+def init_logging(debug_sandbox, debug_dbus):
+    SANDBOX_FORMAT = "%(name)s: %(message)s"
+    DBUS_FORMAT = "%(message)s"
+
+    if debug_sandbox:
+        sandbox_log_handler = logging.StreamHandler()
+        sandbox_log_handler.setFormatter(logging.Formatter(SANDBOX_FORMAT))
+
+        root = logging.getLogger()
+        root.setLevel(logging.DEBUG)
+        root.addHandler(sandbox_log_handler)
+    else:
+        dbus_stderr = logging.getLogger('trackertestutils.dbusdaemon.stderr')
+        dbus_stdout = logging.getLogger('trackertestutils.dbusdaemon.stdout')
+
+        dbus_handler = logging.StreamHandler(stream=sys.stderr)
+        dbus_handler.setFormatter(logging.Formatter(DBUS_FORMAT))
+
+        if debug_dbus:
+            dbus_stderr.setLevel(logging.DEBUG)
+            dbus_stdout.setLevel(logging.DEBUG)
+        else:
+            dbus_stderr.setLevel(logging.INFO)
+            dbus_stdout.setLevel(logging.INFO)
+
+        dbus_stderr.addHandler(dbus_handler)
+        dbus_stdout.addHandler(dbus_handler)
+
+
+class MinerStatusWatch():
+    """This class provides a way to block waiting for miners to finish.
+
+    This is needed because of a deficiency in `tracker index`, see:
+    https://gitlab.gnome.org/GNOME/tracker/issues/122
+
+    """
+    def __init__(self, sandbox, miner_name):
+        self.dbus_name = 'org.freedesktop.Tracker1.Miner.' + miner_name
+        self.object_path = '/org/freedesktop/Tracker1/Miner/' + miner_name
+
+        self._sandbox = sandbox
+
+        # Stores a list of (time, status) pairs. This is used to determine
+        # if the miner has been idle continuously over a time peroid.
+        self._status_log = collections.deque()
+
+    def _log_status(self, time, status):
+        self._status_log.append((time, status))
+        if len(self._status_log) > 100:
+            self._status_log.popleft()
+
+    def setup(self):
+        log.debug(f"Set up status watch on {self.dbus_name}")
+        self._proxy = Gio.DBusProxy.new_sync(
+            self._sandbox.get_connection(),
+            Gio.DBusProxyFlags.NONE, None,
+            self.dbus_name, self.object_path, 'org.freedesktop.Tracker1.Miner',
+            None)
+
+        # FIXME: this doesn't appear to work, so we have to use polling.
+        #proxy.connect('g-signal', miner_signal_cb)
+
+        # This call will raise GDBus.Error:org.freedesktop.DBus.Error.ServiceUnknown
+        # if the miner name is invalid.
+        status = self._proxy.GetStatus()
+        self._log_status(time.time(), status)
+        log.debug(f"{self.dbus_name}: Current status: {status}")
+
+    def check_was_idle_for_time_period(self, period_seconds):
+        now = time.time()
+
+        status = self._proxy.GetStatus()
+        self._log_status(now, status)
+        log.debug(f"{self.dbus_name}: Current status: {status}")
+
+        cursor = len(self._status_log) - 1
+        previous_delta_from_now = 0
+        while True:
+            if cursor < 0 or self._status_log[cursor][1] != 'Idle':
+                if previous_delta_from_now >= period_seconds:
+                    return True
+                else:
+                    return False
+            previous_delta_from_now = (now - self._status_log[cursor][0])
+            cursor -= 1
+
+
+def wait_for_miners(watches):
+    # We wait 1 second after "Idle" status is seen before exiting, because the
+    # extractor goes to/from Idle frequently.
+    wait_for_idle_time = 1
+    while True:
+        status = [watch.check_was_idle_for_time_period(wait_for_idle_time) for watch in watches.values()]
+        if all(status):
+            break
+        else:
+            log.debug(f"Waiting for idle.")
+            time.sleep(0.1)
+
+
+def main():
+    locale.setlocale(locale.LC_ALL, '')
+
+    parser = argument_parser()
+    args = parser.parse_args()
+
+    init_logging(args.debug_sandbox, args.debug_dbus)
+
+    shell = os.environ.get('SHELL', '/bin/bash')
+
+    if args.prefix is None and args.dbus_config is None:
+        parser.print_help()
+        print("\nYou must specify either --dbus-config (to run Tracker from "
+              "a build tree) or --prefix (to run an installed Tracker).")
+        sys.exit(1)
+
+    if args.prefix is not None and args.dbus_config is not None:
+        raise RuntimeError(
+            "You cannot specify --dbus-config and --prefix at the same time. "
+            "Note that running Tracker from the build tree implies "
+            "--dbus-config.")
+
+    if args.verbosity is None:
+        verbosity = verbosity_as_int(os.environ.get('TRACKER_VERBOSITY', 0))
+    else:
+        verbosity = verbosity_as_int(args.verbosity)
+        if 'TRACKER_VERBOSITY' in os.environ:
+            if verbosity != int(os.environ['TRACKER_VERBOSITY']):
+                raise RuntimeError("Incompatible values for TRACKER_VERBOSITY "
+                                   "from environment and from --verbosity "
+                                   "parameter.")
+
+    if args.command is None and args.wait_for_miner is not None:
+        raise RuntimeError("--wait-for-miner cannot be used when opening an "
+                           "interactive shell.")
+
+    index_location = None
+    index_tmpdir = None
+
+    if args.index_location != default_index_location and args.index_tmpdir:
+        raise RuntimeError("The --index-tmpdir flag is enabled, but --index= was also passed.")
+    if args.index_tmpdir:
+        index_location = index_tmpdir = tempfile.mkdtemp(prefix='tracker-sandbox')
+    else:
+        index_location = args.index_location
+
+    # Set up environment variables and foo needed to get started.
+    sandbox = create_sandbox(index_location, args.prefix, verbosity, dbus_config=args.dbus_config)
+    config_set()
+
+    link_to_mime_data()
+
+    miner_watches = {}
+    for miner in (args.wait_for_miner or []):
+        watch = MinerStatusWatch(sandbox, miner)
+        watch.setup()
+        miner_watches[miner] = watch
+
+    try:
+        if args.command:
+            command = [shell, '-c', ' '.join(shlex.quote(c) for c in args.command)]
+            log.debug("Running: %s", command)
+            subprocess.run(command)
+
+            if len(miner_watches) > 0:
+                wait_for_miners(miner_watches)
+        else:
+            if args.dbus_config:
+                print(f"Using Tracker daemons from build tree with D-Bus config {args.dbus_config}")
+            else:
+                print(f"Using Tracker daemons from prefix {args.prefix}")
+            print("Starting interactive Tracker sandbox shell... (type 'exit' to finish)")
+            print()
+
+            os.system(shell)
+    finally:
+        sandbox.stop()
+        if index_tmpdir:
+            shutil.rmtree(index_tmpdir, ignore_errors=True)
+
+
+# Entry point/start
+if __name__ == "__main__":
+    try:
+        main()
+    except RuntimeError as e:
+        sys.stderr.write(f"ERROR: {e}\n")
+        sys.exit(1)
diff --git a/utils/trackertestutils/dbusdaemon.py b/utils/trackertestutils/dbusdaemon.py
index c7e4707f3..641889c11 100644
--- a/utils/trackertestutils/dbusdaemon.py
+++ b/utils/trackertestutils/dbusdaemon.py
@@ -35,17 +35,9 @@ class DaemonNotStartedError(Exception):
 
 
 class DBusDaemon:
-    """The private D-Bus instance that provides the sandbox's session bus.
+    """The private D-Bus instance that provides the sandbox's session bus."""
 
-    We support reading and writing the session information to a file. This
-    means that if the user runs two sandbox instances on the same data
-    directory at the same time, they will share the same message bus.
-
-    """
-
-    def __init__(self, session_file=None):
-        self.session_file = session_file
-        self.existing_session = False
+    def __init__(self):
         self.process = None
 
         self.address = None
@@ -56,19 +48,6 @@ class DBusDaemon:
 
         self._threads = []
 
-        if session_file:
-            try:
-                self.address, self.pid = self.read_session_file(session_file)
-                self.existing_session = True
-            except FileNotFoundError:
-                log.debug("No existing D-Bus session file was found.")
-
-    def get_session_file(self):
-        """Returns the path to the session file if we created it, or None."""
-        if self.existing_session:
-            return None
-        return self.session_file
-
     def get_address(self):
         if self.address is None:
             raise DaemonNotStartedError()
@@ -79,65 +58,35 @@ class DBusDaemon:
             raise DaemonNotStartedError()
         return self._gdbus_connection
 
-    @staticmethod
-    def read_session_file(session_file):
-        with open(session_file, 'r') as f:
-            content = f.read()
+    def start(self, config_file=None, env=None):
+        dbus_command = ['dbus-daemon', '--print-address=1', '--print-pid=1']
+        if config_file:
+            dbus_command += ['--config-file=' + config_file]
+        else:
+            dbus_command += ['--session']
+        log.debug("Running: %s", dbus_command)
+        self.process = subprocess.Popen(
+            dbus_command, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+        self._previous_sigterm_handler = signal.signal(
+            signal.SIGTERM, self._sigterm_handler)
 
         try:
-            address = content.splitlines()[0]
-            pid = int(content.splitlines()[1])
+            self.address = self.process.stdout.readline().strip().decode('ascii')
+            self.pid = int(self.process.stdout.readline().strip().decode('ascii'))
         except ValueError:
-            raise RuntimeError(f"D-Bus session file {session_file} is not valid. "
-                                "Remove this file to start a new session.")
-
-        return address, pid
-
-    @staticmethod
-    def write_session_file(session_file, address, pid):
-        os.makedirs(os.path.dirname(session_file), exist_ok=True)
-
-        content = '%s\n%s' % (address, pid)
-        with open(session_file, 'w') as f:
-            f.write(content)
-
-    def start_if_needed(self, config_file=None, env=None):
-        if self.existing_session:
-            log.debug('Using existing D-Bus session from file "%s" with address "%s"'
-                      ' with PID %d' % (self.session_file, self.address, self.pid))
-        else:
-            dbus_command = ['dbus-daemon', '--print-address=1', '--print-pid=1']
-            if config_file:
-                dbus_command += ['--config-file=' + config_file]
-            else:
-                dbus_command += ['--session']
-            log.debug("Running: %s", dbus_command)
-            self.process = subprocess.Popen(
-                dbus_command, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
-            self._previous_sigterm_handler = signal.signal(
-                signal.SIGTERM, self._sigterm_handler)
-
-            try:
-                self.address = self.process.stdout.readline().strip().decode('ascii')
-                self.pid = int(self.process.stdout.readline().strip().decode('ascii'))
-            except ValueError:
-                error = self.process.stderr.read().strip().decode('unicode-escape')
-                raise RuntimeError(f"Failed to start D-Bus daemon.\n{error}")
-
-            log.debug("Using new D-Bus session with address '%s' with PID %d",
-                      self.address, self.pid)
-
-            if self.session_file:
-                self.write_session_file(self.session_file, self.address, self.pid)
-                log.debug("Wrote D-Bus session file at %s", self.session_file)
-
-            # We must read from the pipes continuously, otherwise the daemon
-            # process will block.
-            self._threads=[threading.Thread(target=self.pipe_to_log, args=(self.process.stdout, 
dbus_stdout_log), daemon=True),
-                           threading.Thread(target=self.pipe_to_log, args=(self.process.stderr, 
dbus_stdout_log), daemon=True)]
-            self._threads[0].start()
-            self._threads[1].start()
+            error = self.process.stderr.read().strip().decode('unicode-escape')
+            raise RuntimeError(f"Failed to start D-Bus daemon.\n{error}")
+
+        log.debug("Using new D-Bus session with address '%s' with PID %d",
+                    self.address, self.pid)
+
+        # We must read from the pipes continuously, otherwise the daemon
+        # process will block.
+        self._threads=[threading.Thread(target=self.pipe_to_log, args=(self.process.stdout, 
dbus_stdout_log), daemon=True),
+                        threading.Thread(target=self.pipe_to_log, args=(self.process.stderr, 
dbus_stdout_log), daemon=True)]
+        self._threads[0].start()
+        self._threads[1].start()
 
         self._gdbus_connection = Gio.DBusConnection.new_for_address_sync(
             self.address,
diff --git a/utils/trackertestutils/helpers.py b/utils/trackertestutils/helpers.py
index fc81b52e6..fbf60513e 100644
--- a/utils/trackertestutils/helpers.py
+++ b/utils/trackertestutils/helpers.py
@@ -463,7 +463,7 @@ class TrackerDBusSandbox:
 
         log.info("Starting D-Bus daemon for sandbox.")
         log.debug("Added environment variables: %s", self.extra_env)
-        self.daemon.start_if_needed(self.dbus_daemon_config_file, env=env)
+        self.daemon.start(self.dbus_daemon_config_file, env=env)
 
     def stop(self):
         tracker_processes = []


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]