commit 3a913b6b92796f2195c28e55ead532a0fef906e6 Author: Damian Johnson atagar@torproject.org Date: Thu Oct 20 09:58:37 2011 -0700
Moving tor launcher into stem function
In writing the stem integ tests I needed a function for starting tor then blocking for its bootstraping to complete. Yesterday Jake mentioned that he could use a launch_tor() function in TorCtl so I'm generalizing this code and moving it into the stem lib. --- stem/__init__.py | 2 +- stem/process.py | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ test/runner.py | 48 ++++++++++------------------------------- 3 files changed, 74 insertions(+), 37 deletions(-)
diff --git a/stem/__init__.py b/stem/__init__.py index 01c350c..5ac77ed 100644 --- a/stem/__init__.py +++ b/stem/__init__.py @@ -2,5 +2,5 @@ Library for working with the tor process. """
-__all__ = ["types"] +__all__ = ["process", "types"]
diff --git a/stem/process.py b/stem/process.py new file mode 100644 index 0000000..f049610 --- /dev/null +++ b/stem/process.py @@ -0,0 +1,61 @@ +""" +Helper functions for working with tor as a process. These are mostly os +dependent, only working on linux, osx, and bsd. +""" + +import os +import signal +import subprocess + +# number of seconds before we time out our attempt to start a tor instance +TOR_INIT_TIMEOUT = 90 + +def launch_tor(torrc_path, init_msg_handler = None): + """ + Initializes a tor process. This blocks until initialization completes or we + error out. + + Arguments: + torrc_path (str) - location of the torrc for us to use + init_msg_handler (functor) - optional functor that will be provided with + tor's initialization stdout as we get it + + Returns: + subprocess.Popen instance for the tor subprocess + + Raises: + OSError if we either fail to create the tor process or reached a timeout + without success + """ + + # double check that we have a torrc to work with + if not os.path.exists(torrc_path): + raise OSError("torrc doesn't exist (%s)" % torrc_path) + + # starts a tor subprocess, raising an OSError if it fails + tor_process = subprocess.Popen(["tor", "-f", torrc_path], stdout = subprocess.PIPE, stderr = subprocess.PIPE) + + # time ourselves out if we reach TOR_INIT_TIMEOUT + def timeout_handler(signum, frame): + # terminates the uninitialized tor process and raise on timeout + tor_process.kill() + raise OSError("reached a %i second timeout without success" % TOR_INIT_TIMEOUT) + + signal.signal(signal.SIGALRM, timeout_handler) + signal.alarm(TOR_INIT_TIMEOUT) + + while True: + init_line = tor_process.stdout.readline().strip() + + # this will provide empty results if the process is terminated + if not init_line: + tor_process.kill() # ... but best make sure + raise OSError("process terminated") + + # provide the caller with the initialization message if they want it + if init_msg_handler: init_msg_handler(init_line) + + # return the process if we're done with bootstrapping + if init_line.endswith("Bootstrapped 100%: Done."): + return tor_process + diff --git a/test/runner.py b/test/runner.py index 6f76d01..c795ea8 100644 --- a/test/runner.py +++ b/test/runner.py @@ -6,9 +6,9 @@ import os import sys import time import shutil -import signal import tempfile -import subprocess + +import stem.process
from stem.util import term
@@ -87,44 +87,20 @@ class Runner: without success """
+ def print_init_line(init_line): + """ + Prints output from tor's stdout while it starts up. + """ + + print term.format(" %s" % init_line, term.Color.BLUE) + print term.format("Starting tor...", term.Color.BLUE, term.Attr.BOLD) start_time = time.time()
try: - # terminate our previous instance before continuing if we had one - if self._tor_process: self._tor_process.kill() - - # double check that we have a torrc to work with - torrc_dst = self.get_torrc_path() - if not os.path.exists(torrc_dst): - raise OSError("torrc doesn't exist (%s)" % torrc_dst) - - # starts a tor subprocess, raising an OSError if it fails - self._tor_process = subprocess.Popen(["tor", "-f", torrc_dst], stdout = subprocess.PIPE, stderr = subprocess.PIPE) - - # time ourselves out if we reach TOR_INIT_TIMEOUT - def timeout_handler(signum, frame): - # terminates the uninitialized tor process and raise on timeout - self._tor_process.kill() - raise OSError("reached a %i second timeout without success" % TOR_INIT_TIMEOUT) - - signal.signal(signal.SIGALRM, timeout_handler) - signal.alarm(TOR_INIT_TIMEOUT) - - while True: - init_line = self._tor_process.stdout.readline().strip() - - # this will provide empty results if the process is terminated - if not init_line: - self._tor_process.kill() # ... but best make sure - raise OSError("process terminated") - - print term.format(" %s" % init_line, term.Color.BLUE) - - # return the process if we're done with bootstrapping - if init_line.endswith("Bootstrapped 100%: Done."): - print term.format(" done (%i seconds)" % (time.time() - start_time), term.Color.BLUE, term.Attr.BOLD) - return + self._tor_process = stem.process.launch_tor(self.get_torrc_path(), print_init_line) + print term.format(" done (%i seconds)" % (time.time() - start_time), term.Color.BLUE, term.Attr.BOLD) + return except OSError, exc: print term.format(" failed to start tor: %s" % exc, term.Color.RED, term.Attr.BOLD) raise exc
tor-commits@lists.torproject.org