summaryrefslogtreecommitdiff
path: root/bitbake/lib/bb
diff options
context:
space:
mode:
authorChris Larson <chris_larson@mentor.com>2010-03-24 16:56:12 -0700
committerRichard Purdie <rpurdie@linux.intel.com>2010-07-02 15:41:32 +0100
commit7acc132cac873e60005516272473a55a8160b9c4 (patch)
tree2e4122862ffd856803160b6089fcb979d3efd630 /bitbake/lib/bb
parentbbf83fd988ca3cf9dae7d2b542a11a7c942b1702 (diff)
downloadopenembedded-core-7acc132cac873e60005516272473a55a8160b9c4.tar.gz
openembedded-core-7acc132cac873e60005516272473a55a8160b9c4.tar.bz2
openembedded-core-7acc132cac873e60005516272473a55a8160b9c4.zip
Formatting cleanups
(Bitbake rev: 2caf134b43a44dad30af4fbe33033b3c58deee57) Signed-off-by: Chris Larson <chris_larson@mentor.com> Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
Diffstat (limited to 'bitbake/lib/bb')
-rw-r--r--bitbake/lib/bb/COW.py20
-rw-r--r--bitbake/lib/bb/build.py11
-rw-r--r--bitbake/lib/bb/cache.py28
-rw-r--r--bitbake/lib/bb/command.py7
-rw-r--r--bitbake/lib/bb/cooker.py25
-rw-r--r--bitbake/lib/bb/daemonize.py295
-rw-r--r--bitbake/lib/bb/data.py35
-rw-r--r--bitbake/lib/bb/data_smart.py46
-rw-r--r--bitbake/lib/bb/event.py5
-rw-r--r--bitbake/lib/bb/fetch/__init__.py32
-rw-r--r--bitbake/lib/bb/fetch/bzr.py7
-rw-r--r--bitbake/lib/bb/fetch/cvs.py2
-rw-r--r--bitbake/lib/bb/fetch/git.py11
-rw-r--r--bitbake/lib/bb/fetch/hg.py7
-rw-r--r--bitbake/lib/bb/fetch/local.py6
-rw-r--r--bitbake/lib/bb/fetch/osc.py10
-rw-r--r--bitbake/lib/bb/fetch/perforce.py8
-rw-r--r--bitbake/lib/bb/fetch/svn.py2
-rw-r--r--bitbake/lib/bb/msg.py2
-rw-r--r--bitbake/lib/bb/parse/ast.py2
-rw-r--r--bitbake/lib/bb/parse/parse_py/BBHandler.py2
-rw-r--r--bitbake/lib/bb/parse/parse_py/ConfHandler.py2
-rw-r--r--bitbake/lib/bb/persist_data.py13
-rw-r--r--bitbake/lib/bb/providers.py16
-rw-r--r--bitbake/lib/bb/runqueue.py93
-rw-r--r--bitbake/lib/bb/server/none.py1
-rw-r--r--bitbake/lib/bb/server/xmlrpc.py9
-rw-r--r--bitbake/lib/bb/shell.py8
-rw-r--r--bitbake/lib/bb/taskdata.py24
-rw-r--r--bitbake/lib/bb/ui/__init__.py1
-rw-r--r--bitbake/lib/bb/ui/crumbs/__init__.py1
-rw-r--r--bitbake/lib/bb/ui/crumbs/buildmanager.py39
-rw-r--r--bitbake/lib/bb/ui/crumbs/runningbuild.py24
-rw-r--r--bitbake/lib/bb/ui/depexp.py3
-rw-r--r--bitbake/lib/bb/ui/goggle.py13
-rw-r--r--bitbake/lib/bb/ui/knotty.py2
-rw-r--r--bitbake/lib/bb/ui/ncurses.py7
-rw-r--r--bitbake/lib/bb/ui/puccho.py110
-rw-r--r--bitbake/lib/bb/ui/uievent.py5
-rw-r--r--bitbake/lib/bb/utils.py185
40 files changed, 544 insertions, 575 deletions
diff --git a/bitbake/lib/bb/COW.py b/bitbake/lib/bb/COW.py
index ca206cf4b4..224213db5c 100644
--- a/bitbake/lib/bb/COW.py
+++ b/bitbake/lib/bb/COW.py
@@ -3,7 +3,7 @@
#
# This is a copy on write dictionary and set which abuses classes to try and be nice and fast.
#
-# Copyright (C) 2006 Tim Amsell
+# Copyright (C) 2006 Tim Amsell
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
@@ -18,7 +18,7 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
-#Please Note:
+#Please Note:
# Be careful when using mutable types (ie Dict and Lists) - operations involving these are SLOW.
# Assign a file to __warn__ to get warnings about slow operations.
#
@@ -40,7 +40,7 @@ MUTABLE = "__mutable__"
class COWMeta(type):
pass
-
+
class COWDictMeta(COWMeta):
__warn__ = False
__hasmutable__ = False
@@ -64,7 +64,7 @@ class COWDictMeta(COWMeta):
cls.__hasmutable__ = True
key += MUTABLE
setattr(cls, key, value)
-
+
def __getmutable__(cls, key, readonly=False):
nkey = key + MUTABLE
try:
@@ -98,8 +98,8 @@ class COWDictMeta(COWMeta):
value = getattr(cls, key)
except AttributeError:
value = cls.__getmutable__(key, readonly)
-
- # This is for values which have been deleted
+
+ # This is for values which have been deleted
if value is cls.__marker__:
raise AttributeError("key %s does not exist." % key)
@@ -127,7 +127,7 @@ class COWDictMeta(COWMeta):
def iter(cls, type, readonly=False):
for key in dir(cls):
if key.startswith("__"):
- continue
+ continue
if key.endswith(MUTABLE):
key = key[:-len(MUTABLE)]
@@ -176,13 +176,13 @@ class COWSetMeta(COWDictMeta):
def remove(cls, value):
COWDictMeta.__delitem__(cls, repr(hash(value)))
-
+
def __in__(cls, value):
return COWDictMeta.has_key(repr(hash(value)))
def iterkeys(cls):
raise TypeError("sets don't have keys")
-
+
def iteritems(cls):
raise TypeError("sets don't have 'items'")
@@ -286,7 +286,7 @@ if __name__ == "__main__":
print "Boo!"
else:
print "Yay - has_key with delete works!"
-
+
print "a", a
for x in a.iteritems():
print x
diff --git a/bitbake/lib/bb/build.py b/bitbake/lib/bb/build.py
index 16d69281f1..7ca1663b7c 100644
--- a/bitbake/lib/bb/build.py
+++ b/bitbake/lib/bb/build.py
@@ -28,7 +28,7 @@
from bb import data, event, mkdirhier, utils
import bb, os, sys
-# When we execute a python function we'd like certain things
+# When we execute a python function we'd like certain things
# in all namespaces, hence we add them to __builtins__
# If we do not do this and use the exec globals, they will
# not be available to subfunctions.
@@ -212,7 +212,7 @@ def exec_func_python(func, d, runfile, logfile):
try:
utils.better_exec(comp, {"d": d}, tmp, bbfile)
except:
- (t,value,tb) = sys.exc_info()
+ (t, value, tb) = sys.exc_info()
if t in [bb.parse.SkipPackage, bb.build.FuncFailed]:
raise
@@ -303,8 +303,8 @@ def exec_task(task, d):
def extract_stamp(d, fn):
"""
- Extracts stamp format which is either a data dictonary (fn unset)
- or a dataCache entry (fn set).
+ Extracts stamp format which is either a data dictonary (fn unset)
+ or a dataCache entry (fn set).
"""
if fn:
return d.stamp[fn]
@@ -361,7 +361,7 @@ def add_tasks(tasklist, d):
if not task in task_deps['tasks']:
task_deps['tasks'].append(task)
- flags = data.getVarFlags(task, d)
+ flags = data.getVarFlags(task, d)
def getTask(name):
if not name in task_deps:
task_deps[name] = {}
@@ -387,4 +387,3 @@ def remove_task(task, kill, d):
If kill is 1, also remove tasks that depend on this task."""
data.delVarFlag(task, 'task', d)
-
diff --git a/bitbake/lib/bb/cache.py b/bitbake/lib/bb/cache.py
index 106621911b..300acc5fc6 100644
--- a/bitbake/lib/bb/cache.py
+++ b/bitbake/lib/bb/cache.py
@@ -73,7 +73,7 @@ class Cache:
# cache there isn't even any point in loading it...
newest_mtime = 0
deps = bb.data.getVar("__depends", data, True)
- for f,old_mtime in deps:
+ for f, old_mtime in deps:
if old_mtime > newest_mtime:
newest_mtime = old_mtime
@@ -102,10 +102,10 @@ class Cache:
"""
Gets the value of a variable
(similar to getVar in the data class)
-
+
There are two scenarios:
1. We have cached data - serve from depends_cache[fn]
- 2. We're learning what data to cache - serve from data
+ 2. We're learning what data to cache - serve from data
backend but add a copy of the data to the cache.
"""
if fn in self.clean:
@@ -134,7 +134,7 @@ class Cache:
self.data = data
# Make sure __depends makes the depends_cache
- # If we're a virtual class we need to make sure all our depends are appended
+ # If we're a virtual class we need to make sure all our depends are appended
# to the depends of fn.
depends = self.getVar("__depends", virtualfn, True) or []
self.depends_cache.setdefault(fn, {})
@@ -259,7 +259,7 @@ class Cache:
self.remove(fn)
return False
- mtime = bb.parse.cached_mtime_noerror(fn)
+ mtime = bb.parse.cached_mtime_noerror(fn)
# Check file still exists
if mtime == 0:
@@ -276,7 +276,7 @@ class Cache:
# Check dependencies are still valid
depends = self.getVar("__depends", fn, True)
if depends:
- for f,old_mtime in depends:
+ for f, old_mtime in depends:
fmtime = bb.parse.cached_mtime_noerror(f)
# Check if file still exists
if old_mtime != 0 and fmtime == 0:
@@ -346,7 +346,7 @@ class Cache:
def handle_data(self, file_name, cacheData):
"""
- Save data we need into the cache
+ Save data we need into the cache
"""
pn = self.getVar('PN', file_name, True)
@@ -372,7 +372,7 @@ class Cache:
# build FileName to PackageName lookup table
cacheData.pkg_fn[file_name] = pn
- cacheData.pkg_pepvpr[file_name] = (pe,pv,pr)
+ cacheData.pkg_pepvpr[file_name] = (pe, pv, pr)
cacheData.pkg_dp[file_name] = dp
provides = [pn]
@@ -401,13 +401,13 @@ class Cache:
if not dep in cacheData.all_depends:
cacheData.all_depends.append(dep)
- # Build reverse hash for PACKAGES, so runtime dependencies
+ # Build reverse hash for PACKAGES, so runtime dependencies
# can be be resolved (RDEPENDS, RRECOMMENDS etc.)
for package in packages:
if not package in cacheData.packages:
cacheData.packages[package] = []
cacheData.packages[package].append(file_name)
- rprovides += (self.getVar("RPROVIDES_%s" % package, file_name, 1) or "").split()
+ rprovides += (self.getVar("RPROVIDES_%s" % package, file_name, 1) or "").split()
for package in packages_dynamic:
if not package in cacheData.packages_dynamic:
@@ -472,12 +472,12 @@ class Cache:
def init(cooker):
"""
- The Objective: Cache the minimum amount of data possible yet get to the
+ The Objective: Cache the minimum amount of data possible yet get to the
stage of building packages (i.e. tryBuild) without reparsing any .bb files.
- To do this, we intercept getVar calls and only cache the variables we see
- being accessed. We rely on the cache getVar calls being made for all
- variables bitbake might need to use to reach this stage. For each cached
+ To do this, we intercept getVar calls and only cache the variables we see
+ being accessed. We rely on the cache getVar calls being made for all
+ variables bitbake might need to use to reach this stage. For each cached
file we need to track:
* Its mtime
diff --git a/bitbake/lib/bb/command.py b/bitbake/lib/bb/command.py
index 06bd203c90..a590e61abe 100644
--- a/bitbake/lib/bb/command.py
+++ b/bitbake/lib/bb/command.py
@@ -20,7 +20,7 @@ Provide an interface to interact with the bitbake server through 'commands'
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""
-The bitbake server takes 'commands' from its UI/commandline.
+The bitbake server takes 'commands' from its UI/commandline.
Commands are either synchronous or asynchronous.
Async commands return data to the client in the form of events.
Sync commands must only return data through the function return value
@@ -62,7 +62,7 @@ class Command:
try:
command = commandline.pop(0)
if command in CommandsSync.__dict__:
- # Can run synchronous commands straight away
+ # Can run synchronous commands straight away
return getattr(CommandsSync, command)(self.cmds_sync, self, commandline)
if self.currentAsyncCommand is not None:
return "Busy (%s in progress)" % self.currentAsyncCommand[0]
@@ -268,6 +268,3 @@ class CookerCommandSetExitCode(bb.event.Event):
def __init__(self, exitcode):
bb.event.Event.__init__(self)
self.exitcode = int(exitcode)
-
-
-
diff --git a/bitbake/lib/bb/cooker.py b/bitbake/lib/bb/cooker.py
index a413c8a854..743e4be06b 100644
--- a/bitbake/lib/bb/cooker.py
+++ b/bitbake/lib/bb/cooker.py
@@ -181,7 +181,7 @@ class BBCooker:
def tryBuild(self, fn, task):
"""
- Build a provider and its dependencies.
+ Build a provider and its dependencies.
build_depends is a list of previous build dependencies (not runtime)
If build_depends is empty, we're dealing with a runtime depends
"""
@@ -206,7 +206,7 @@ class BBCooker:
# Sort by priority
for pn in pkg_pn:
- (last_ver,last_file,pref_ver,pref_file) = bb.providers.findBestProvider(pn, self.configuration.data, self.status)
+ (last_ver, last_file, pref_ver, pref_file) = bb.providers.findBestProvider(pn, self.configuration.data, self.status)
preferred_versions[pn] = (pref_ver, pref_file)
latest_versions[pn] = (last_ver, last_file)
@@ -315,7 +315,7 @@ class BBCooker:
rq = bb.runqueue.RunQueue(self, self.configuration.data, self.status, taskdata, runlist)
rq.prepare_runqueue()
- seen_fnids = []
+ seen_fnids = []
depend_tree = {}
depend_tree["depends"] = {}
depend_tree["tdepends"] = {}
@@ -352,7 +352,7 @@ class BBCooker:
depend_tree["rdepends-pn"][pn] = []
for rdep in taskdata.rdepids[fnid]:
- depend_tree["rdepends-pn"][pn].append(taskdata.run_names_index[rdep])
+ depend_tree["rdepends-pn"][pn].append(taskdata.run_names_index[rdep])
rdepends = self.status.rundeps[fn]
for package in rdepends:
@@ -542,7 +542,7 @@ class BBCooker:
# Nomally we only register event handlers at the end of parsing .bb files
# We register any handlers we've found so far here...
for var in data.getVar('__BBHANDLERS', self.configuration.data) or []:
- bb.event.register(var,bb.data.getVar(var, self.configuration.data))
+ bb.event.register(var, bb.data.getVar(var, self.configuration.data))
bb.fetch.fetcher_init(self.configuration.data)
@@ -583,7 +583,7 @@ class BBCooker:
"""
if not bb.data.getVar("BUILDNAME", self.configuration.data):
bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data)
- bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()), self.configuration.data)
+ bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S', time.gmtime()), self.configuration.data)
def matchFiles(self, buildfile):
"""
@@ -775,10 +775,10 @@ class BBCooker:
ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
self.status.ignored_dependencies = set(ignore.split())
-
+
for dep in self.configuration.extra_assume_provided:
self.status.ignored_dependencies.add(dep)
-
+
self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
bb.msg.debug(1, bb.msg.domain.Collection, "collecting .bb files")
@@ -816,7 +816,7 @@ class BBCooker:
for f in contents:
(root, ext) = os.path.splitext(f)
if ext == ".bb":
- bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
+ bbfiles.append(os.path.abspath(os.path.join(os.getcwd(), f)))
return bbfiles
def find_bbfiles( self, path ):
@@ -828,7 +828,7 @@ class BBCooker:
for ignored in ('SCCS', 'CVS', '.svn'):
if ignored in dirs:
dirs.remove(ignored)
- found += [join(dir,f) for f in files if f.endswith('.bb')]
+ found += [join(dir, f) for f in files if f.endswith('.bb')]
return found
@@ -912,9 +912,9 @@ class BBCooker:
pout.close()
else:
self.server.serve_forever()
-
+
bb.event.fire(CookerExit(), self.configuration.event_data)
-
+
class CookerExit(bb.event.Event):
"""
Notify clients of the Cooker shutdown
@@ -984,4 +984,3 @@ class CookerParser:
raise ParsingErrorsFound
return False
return True
-
diff --git a/bitbake/lib/bb/daemonize.py b/bitbake/lib/bb/daemonize.py
index 1a8bb379f4..a944af2238 100644
--- a/bitbake/lib/bb/daemonize.py
+++ b/bitbake/lib/bb/daemonize.py
@@ -3,17 +3,17 @@ Python Deamonizing helper
Configurable daemon behaviors:
- 1.) The current working directory set to the "/" directory.
- 2.) The current file creation mode mask set to 0.
- 3.) Close all open files (1024).
- 4.) Redirect standard I/O streams to "/dev/null".
+ 1.) The current working directory set to the "/" directory.
+ 2.) The current file creation mode mask set to 0.
+ 3.) Close all open files (1024).
+ 4.) Redirect standard I/O streams to "/dev/null".
A failed call to fork() now raises an exception.
References:
- 1) Advanced Programming in the Unix Environment: W. Richard Stevens
- 2) Unix Programming Frequently Asked Questions:
- http://www.erlenstar.demon.co.uk/unix/faq_toc.html
+ 1) Advanced Programming in the Unix Environment: W. Richard Stevens
+ 2) Unix Programming Frequently Asked Questions:
+ http://www.erlenstar.demon.co.uk/unix/faq_toc.html
Modified to allow a function to be daemonized and return for
bitbake use by Richard Purdie
@@ -24,8 +24,8 @@ __copyright__ = "Copyright (C) 2005 Chad J. Schroeder"
__version__ = "0.2"
# Standard Python modules.
-import os # Miscellaneous OS interfaces.
-import sys # System-specific parameters and functions.
+import os # Miscellaneous OS interfaces.
+import sys # System-specific parameters and functions.
# Default daemon parameters.
# File mode creation mask of the daemon.
@@ -37,155 +37,154 @@ MAXFD = 1024
# The standard I/O file descriptors are redirected to /dev/null by default.
if (hasattr(os, "devnull")):
- REDIRECT_TO = os.devnull
+ REDIRECT_TO = os.devnull
else:
- REDIRECT_TO = "/dev/null"
+ REDIRECT_TO = "/dev/null"
def createDaemon(function, logfile):
- """
- Detach a process from the controlling terminal and run it in the
- background as a daemon, returning control to the caller.
- """
-
- try:
- # Fork a child process so the parent can exit. This returns control to
- # the command-line or shell. It also guarantees that the child will not
- # be a process group leader, since the child receives a new process ID
- # and inherits the parent's process group ID. This step is required
- # to insure that the next call to os.setsid is successful.
- pid = os.fork()
- except OSError, e:
- raise Exception, "%s [%d]" % (e.strerror, e.errno)
-
- if (pid == 0): # The first child.
- # To become the session leader of this new session and the process group
- # leader of the new process group, we call os.setsid(). The process is
- # also guaranteed not to have a controlling terminal.
- os.setsid()
-
- # Is ignoring SIGHUP necessary?
- #
- # It's often suggested that the SIGHUP signal should be ignored before
- # the second fork to avoid premature termination of the process. The
- # reason is that when the first child terminates, all processes, e.g.
- # the second child, in the orphaned group will be sent a SIGHUP.
- #
- # "However, as part of the session management system, there are exactly
- # two cases where SIGHUP is sent on the death of a process:
- #
- # 1) When the process that dies is the session leader of a session that
- # is attached to a terminal device, SIGHUP is sent to all processes
- # in the foreground process group of that terminal device.
- # 2) When the death of a process causes a process group to become
- # orphaned, and one or more processes in the orphaned group are
- # stopped, then SIGHUP and SIGCONT are sent to all members of the
- # orphaned group." [2]
- #
- # The first case can be ignored since the child is guaranteed not to have
- # a controlling terminal. The second case isn't so easy to dismiss.
- # The process group is orphaned when the first child terminates and
- # POSIX.1 requires that every STOPPED process in an orphaned process
- # group be sent a SIGHUP signal followed by a SIGCONT signal. Since the
- # second child is not STOPPED though, we can safely forego ignoring the
- # SIGHUP signal. In any case, there are no ill-effects if it is ignored.
- #
- # import signal # Set handlers for asynchronous events.
- # signal.signal(signal.SIGHUP, signal.SIG_IGN)
-
- try:
- # Fork a second child and exit immediately to prevent zombies. This
- # causes the second child process to be orphaned, making the init
- # process responsible for its cleanup. And, since the first child is
- # a session leader without a controlling terminal, it's possible for
- # it to acquire one by opening a terminal in the future (System V-
- # based systems). This second fork guarantees that the child is no
- # longer a session leader, preventing the daemon from ever acquiring
- # a controlling terminal.
- pid = os.fork() # Fork a second child.
- except OSError, e:
- raise Exception, "%s [%d]" % (e.strerror, e.errno)
-
- if (pid == 0): # The second child.
- # We probably don't want the file mode creation mask inherited from
- # the parent, so we give the child complete control over permissions.
- if UMASK is not None:
- os.umask(UMASK)
- else:
- # Parent (the first child) of the second child.
- os._exit(0)
- else:
- # exit() or _exit()?
- # _exit is like exit(), but it doesn't call any functions registered
- # with atexit (and on_exit) or any registered signal handlers. It also
- # closes any open file descriptors. Using exit() may cause all stdio
- # streams to be flushed twice and any temporary files may be unexpectedly
- # removed. It's therefore recommended that child branches of a fork()
- # and the parent branch(es) of a daemon use _exit().
- return
-
- # Close all open file descriptors. This prevents the child from keeping
- # open any file descriptors inherited from the parent. There is a variety
- # of methods to accomplish this task. Three are listed below.
- #
- # Try the system configuration variable, SC_OPEN_MAX, to obtain the maximum
- # number of open file descriptors to close. If it doesn't exists, use
- # the default value (configurable).
- #
- # try:
- # maxfd = os.sysconf("SC_OPEN_MAX")
- # except (AttributeError, ValueError):
- # maxfd = MAXFD
- #
- # OR
- #
- # if (os.sysconf_names.has_key("SC_OPEN_MAX")):
- # maxfd = os.sysconf("SC_OPEN_MAX")
- # else:
- # maxfd = MAXFD
- #
- # OR
- #
- # Use the getrlimit method to retrieve the maximum file descriptor number
- # that can be opened by this process. If there is not limit on the
- # resource, use the default value.
- #
- import resource # Resource usage information.
- maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
- if (maxfd == resource.RLIM_INFINITY):
- maxfd = MAXFD
+ """
+ Detach a process from the controlling terminal and run it in the
+ background as a daemon, returning control to the caller.
+ """
+
+ try:
+ # Fork a child process so the parent can exit. This returns control to
+ # the command-line or shell. It also guarantees that the child will not
+ # be a process group leader, since the child receives a new process ID
+ # and inherits the parent's process group ID. This step is required
+ # to insure that the next call to os.setsid is successful.
+ pid = os.fork()
+ except OSError, e:
+ raise Exception, "%s [%d]" % (e.strerror, e.errno)
+
+ if (pid == 0): # The first child.
+ # To become the session leader of this new session and the process group
+ # leader of the new process group, we call os.setsid(). The process is
+ # also guaranteed not to have a controlling terminal.
+ os.setsid()
+
+ # Is ignoring SIGHUP necessary?
+ #
+ # It's often suggested that the SIGHUP signal should be ignored before
+ # the second fork to avoid premature termination of the process. The
+ # reason is that when the first child terminates, all processes, e.g.
+ # the second child, in the orphaned group will be sent a SIGHUP.
+ #
+ # "However, as part of the session management system, there are exactly
+ # two cases where SIGHUP is sent on the death of a process:
+ #
+ # 1) When the process that dies is the session leader of a session that
+ # is attached to a terminal device, SIGHUP is sent to all processes
+ # in the foreground process group of that terminal device.
+ # 2) When the death of a process causes a process group to become
+ # orphaned, and one or more processes in the orphaned group are
+ # stopped, then SIGHUP and SIGCONT are sent to all members of the
+ # orphaned group." [2]
+ #
+ # The first case can be ignored since the child is guaranteed not to have
+ # a controlling terminal. The second case isn't so easy to dismiss.
+ # The process group is orphaned when the first child terminates and
+ # POSIX.1 requires that every STOPPED process in an orphaned process
+ # group be sent a SIGHUP signal followed by a SIGCONT signal. Since the
+ # second child is not STOPPED though, we can safely forego ignoring the
+ # SIGHUP signal. In any case, there are no ill-effects if it is ignored.
+ #
+ # import signal # Set handlers for asynchronous events.
+ # signal.signal(signal.SIGHUP, signal.SIG_IGN)
+
+ try:
+ # Fork a second child and exit immediately to prevent zombies. This
+ # causes the second child process to be orphaned, making the init
+ # process responsible for its cleanup. And, since the first child is
+ # a session leader without a controlling terminal, it's possible for
+ # it to acquire one by opening a terminal in the future (System V-
+ # based systems). This second fork guarantees that the child is no
+ # longer a session leader, preventing the daemon from ever acquiring
+ # a controlling terminal.
+ pid = os.fork() # Fork a second child.
+ except OSError, e:
+ raise Exception, "%s [%d]" % (e.strerror, e.errno)
+
+ if (pid == 0): # The second child.
+ # We probably don't want the file mode creati