diff -Nru python-daemonize-2.3.1/daemonize.py python-daemonize-2.4.7/daemonize.py --- python-daemonize-2.3.1/daemonize.py 2014-05-28 18:13:57.000000000 +0000 +++ python-daemonize-2.4.7/daemonize.py 2016-07-28 16:15:53.000000000 +0000 @@ -10,29 +10,41 @@ import logging import atexit from logging import handlers +import traceback + + +__version__ = "2.4.7" class Daemonize(object): - """ Daemonize object - Object constructor expects three arguments: - - app: contains the application name which will be sent to syslog. - - pid: path to the pidfile. - - action: your custom function which will be executed after daemonization. - - keep_fds: optional list of fds which should not be closed. - - auto_close_fds: optional parameter to not close opened fds. - - privileged_action: action that will be executed before drop privileges if user or - group parameter is provided. - If you want to transfer anything from privileged_action to action, such as - opened privileged file descriptor, you should return it from - privileged_action function and catch it inside action function. - - user: drop privileges to this user if provided. - - group: drop privileges to this group if provided. - - verbose: send debug messages to logger if provided. - - logger: use this logger object instead of creating new one, if provided. """ - def __init__(self, app, pid, action, keep_fds=None, auto_close_fds=True, privileged_action=None, user=None, group=None, verbose=False, logger=None): + Daemonize object. + + Object constructor expects three arguments. + + :param app: contains the application name which will be sent to syslog. + :param pid: path to the pidfile. + :param action: your custom function which will be executed after daemonization. + :param keep_fds: optional list of fds which should not be closed. + :param auto_close_fds: optional parameter to not close opened fds. + :param privileged_action: action that will be executed before drop privileges if user or + group parameter is provided. + If you want to transfer anything from privileged_action to action, such as + opened privileged file descriptor, you should return it from + privileged_action function and catch it inside action function. + :param user: drop privileges to this user if provided. + :param group: drop privileges to this group if provided. + :param verbose: send debug messages to logger if provided. + :param logger: use this logger object instead of creating new one, if provided. + :param foreground: stay in foreground; do not fork (for debugging) + :param chdir: change working directory if provided or / + """ + def __init__(self, app, pid, action, + keep_fds=None, auto_close_fds=True, privileged_action=None, + user=None, group=None, verbose=False, logger=None, + foreground=False, chdir="/"): self.app = app - self.pid = pid + self.pid = os.path.abspath(pid) self.action = action self.keep_fds = keep_fds or [] self.privileged_action = privileged_action or (lambda: ()) @@ -41,17 +53,18 @@ self.logger = logger self.verbose = verbose self.auto_close_fds = auto_close_fds + self.foreground = foreground + self.chdir = chdir def sigterm(self, signum, frame): - """ sigterm method + """ These actions will be done after SIGTERM. """ self.logger.warn("Caught signal %s. Stopping daemon." % signum) - os.remove(self.pid) sys.exit(0) def exit(self): - """ exit method + """ Cleanup pid file at exit. """ self.logger.warn("Stopping daemon.") @@ -59,8 +72,8 @@ sys.exit(0) def start(self): - """ start method - Main daemonization process. + """ + Start daemonization process. """ # If pidfile already exists, we should read pid from there; to overwrite it, if locking # will fail, because locking attempt somehow purges the file contents. @@ -84,47 +97,52 @@ pidfile.write(old_pid) sys.exit(1) - # Fork, creating a new process for the child. - process_id = os.fork() - if process_id < 0: - # Fork error. Exit badly. - sys.exit(1) - elif process_id != 0: - # This is the parent process. Exit. - sys.exit(0) - # This is the child process. Continue. - - # Stop listening for signals that the parent process receives. - # This is done by getting a new process id. - # setpgrp() is an alternative to setsid(). - # setsid puts the process in a new parent group and detaches its controlling terminal. - process_id = os.setsid() - if process_id == -1: - # Uh oh, there was a problem. - sys.exit(1) + # skip fork if foreground is specified + if not self.foreground: + # Fork, creating a new process for the child. + try: + process_id = os.fork() + except OSError as e: + self.logger.error("Unable to fork, errno: {0}".format(e.errno)) + sys.exit(1) + if process_id != 0: + # This is the parent process. Exit without cleanup, + # see https://github.com/thesharp/daemonize/issues/46 + os._exit(0) + # This is the child process. Continue. + + # Stop listening for signals that the parent process receives. + # This is done by getting a new process id. + # setpgrp() is an alternative to setsid(). + # setsid puts the process in a new parent group and detaches its controlling terminal. + process_id = os.setsid() + if process_id == -1: + # Uh oh, there was a problem. + sys.exit(1) - # Add lockfile to self.keep_fds. - self.keep_fds.append(lockfile.fileno()) + # Add lockfile to self.keep_fds. + self.keep_fds.append(lockfile.fileno()) - # Close all file descriptors, except the ones mentioned in self.keep_fds. - devnull = "/dev/null" - if hasattr(os, "devnull"): - # Python has set os.devnull on this system, use it instead as it might be different - # than /dev/null. - devnull = os.devnull - - if self.auto_close_fds: - for fd in range(3, resource.getrlimit(resource.RLIMIT_NOFILE)[0]): - if fd not in self.keep_fds: - try: - os.close(fd) - except OSError: - pass - - devnull_fd = os.open(devnull, os.O_RDWR) - os.dup2(devnull_fd, 0) - os.dup2(devnull_fd, 1) - os.dup2(devnull_fd, 2) + # Close all file descriptors, except the ones mentioned in self.keep_fds. + devnull = "/dev/null" + if hasattr(os, "devnull"): + # Python has set os.devnull on this system, use it instead as it might be different + # than /dev/null. + devnull = os.devnull + + if self.auto_close_fds: + for fd in range(3, resource.getrlimit(resource.RLIMIT_NOFILE)[0]): + if fd not in self.keep_fds: + try: + os.close(fd) + except OSError: + pass + + devnull_fd = os.open(devnull, os.O_RDWR) + os.dup2(devnull_fd, 0) + os.dup2(devnull_fd, 1) + os.dup2(devnull_fd, 2) + os.close(devnull_fd) if self.logger is None: # Initialize logging. @@ -142,7 +160,7 @@ # We will continue with syslog initialization only if actually have such capabilities # on the machine we are running this. - if os.path.isfile(syslog_address): + if os.path.exists(syslog_address): syslog = handlers.SysLogHandler(syslog_address) if self.verbose: syslog.setLevel(logging.DEBUG) @@ -161,20 +179,35 @@ # Change to a known directory. If this isn't done, starting a daemon in a subdirectory that # needs to be deleted results in "directory busy" errors. - os.chdir("/") + os.chdir(self.chdir) # Execute privileged action privileged_action_result = self.privileged_action() if not privileged_action_result: privileged_action_result = [] - # Change gid + # Change owner of pid file, it's required because pid file will be removed at exit. + uid, gid = -1, -1 + if self.group: try: gid = grp.getgrnam(self.group).gr_gid except KeyError: self.logger.error("Group {0} not found".format(self.group)) sys.exit(1) + + if self.user: + try: + uid = pwd.getpwnam(self.user).pw_uid + except KeyError: + self.logger.error("User {0} not found.".format(self.user)) + sys.exit(1) + + if uid != -1 or gid != -1: + os.chown(self.pid, uid, gid) + + # Change gid + if self.group: try: os.setgid(gid) except OSError: @@ -208,4 +241,8 @@ self.logger.warn("Starting daemon.") - self.action(*privileged_action_result) + try: + self.action(*privileged_action_result) + except Exception: + for line in traceback.format_exc().split("\n"): + self.logger.error(line) diff -Nru python-daemonize-2.3.1/debian/changelog python-daemonize-2.4.7/debian/changelog --- python-daemonize-2.3.1/debian/changelog 2014-11-13 21:02:44.000000000 +0000 +++ python-daemonize-2.4.7/debian/changelog 2017-10-21 17:26:03.000000000 +0000 @@ -1,5 +1,5 @@ -python-daemonize (2.3.1-1) unstable; urgency=medium +python-daemonize (2.4.7-xenial) xenial; urgency=medium - * Initial release. (Closes: #732603) + * Build for latest daemonize 2.4.7. - -- Thomas Goirand Sat, 01 Nov 2014 01:52:44 +0800 + -- Luke Horwell Sat, 21 Oct 2017 18:26:02 +0800 diff -Nru python-daemonize-2.3.1/debian/source/format python-daemonize-2.4.7/debian/source/format --- python-daemonize-2.3.1/debian/source/format 2014-11-13 21:02:44.000000000 +0000 +++ python-daemonize-2.4.7/debian/source/format 2017-10-21 17:26:22.000000000 +0000 @@ -1 +1 @@ -3.0 (quilt) +3.0 (native) diff -Nru python-daemonize-2.3.1/docs/conf.py python-daemonize-2.4.7/docs/conf.py --- python-daemonize-2.3.1/docs/conf.py 1970-01-01 00:00:00.000000000 +0000 +++ python-daemonize-2.4.7/docs/conf.py 2016-07-28 16:15:53.000000000 +0000 @@ -0,0 +1,267 @@ +# -*- coding: utf-8 -*- +# +# daemonize documentation build configuration file, created by +# sphinx-quickstart on Mon Nov 2 17:36:41 2015. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath('..')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.viewcode', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'daemonize' +copyright = u'2015, Ilya Otyutskiy' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. + +from daemonize import __version__ + +version = __version__ +release = __version__ +# The full version, including alpha/beta/rc tags. + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +import sphinx_rtd_theme + +html_theme = "sphinx_rtd_theme" + +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'daemonizedoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ('index', 'daemonize.tex', u'daemonize Documentation', + u'Ilya Otyutskiy', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'daemonize', u'daemonize Documentation', + [u'Ilya Otyutskiy'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'daemonize', u'daemonize Documentation', + u'Ilya Otyutskiy', 'daemonize', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False diff -Nru python-daemonize-2.3.1/docs/index.rst python-daemonize-2.4.7/docs/index.rst --- python-daemonize-2.3.1/docs/index.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-daemonize-2.4.7/docs/index.rst 2016-07-28 16:15:53.000000000 +0000 @@ -0,0 +1,21 @@ +.. daemonize documentation master file, created by + sphinx-quickstart on Mon Nov 2 17:36:41 2015. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +.. include:: ../README.rst + +API +--- + +.. automodule:: daemonize + :members: + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff -Nru python-daemonize-2.3.1/.gitignore python-daemonize-2.4.7/.gitignore --- python-daemonize-2.3.1/.gitignore 2014-05-28 18:13:57.000000000 +0000 +++ python-daemonize-2.4.7/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -*.pyc -.ropeproject -__pycache__ -build -daemonize.egg-info -dist diff -Nru python-daemonize-2.3.1/Makefile python-daemonize-2.4.7/Makefile --- python-daemonize-2.3.1/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ python-daemonize-2.4.7/Makefile 2016-07-28 16:15:53.000000000 +0000 @@ -0,0 +1,10 @@ +all: clean upload + +clean: + rm -rf dist daemonize.egg-info + +upload: + python setup.py sdist bdist_wheel upload + +docs: + sphinx-build -b html docs docs/_build diff -Nru python-daemonize-2.3.1/MANIFEST.in python-daemonize-2.4.7/MANIFEST.in --- python-daemonize-2.3.1/MANIFEST.in 2014-05-28 18:13:57.000000000 +0000 +++ python-daemonize-2.4.7/MANIFEST.in 2016-07-28 16:15:53.000000000 +0000 @@ -1,3 +1,6 @@ include MANIFEST.in -include README.md +include README.rst include LICENSE + +graft docs +recursive-exclude docs *.pyc *.pyo \ No newline at end of file diff -Nru python-daemonize-2.3.1/README.md python-daemonize-2.4.7/README.md --- python-daemonize-2.3.1/README.md 2014-05-28 18:13:57.000000000 +0000 +++ python-daemonize-2.4.7/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -# daemonize [![Build Status](https://secure.travis-ci.org/thesharp/daemonize.png)](http://travis-ci.org/thesharp/daemonize) - -## Description -**daemonize** is a library for writing system daemons in Python. It has some bits from [daemonize.sourceforge.net](http://daemonize.sourceforge.net). It is distributed under MIT license. - -## Dependencies -It is tested under following Python versions: - -- 2.6 -- 2.7 -- 3.3 - - -## Installation -You can install it from Python Package Index (PyPI): - - $ pip install daemonize - -## Usage -```python -from time import sleep -from daemonize import Daemonize - -pid = "/tmp/test.pid" - - -def main(): - while True: - sleep(5) - -daemon = Daemonize(app="test_app", pid=pid, action=main) -daemon.start() -``` - -## File descriptors -Daemonize object's constructor understands the optional argument **keep_fds** which contains a list of FDs which should not be closed. For example: -```python -import logging -from daemonize import Daemonize - -pid = "/tmp/test.pid" -logger = logging.getLogger(__name__) -logger.setLevel(logging.DEBUG) -logger.propagate = False -fh = logging.FileHandler("/tmp/test.log", "w") -fh.setLevel(logging.DEBUG) -logger.addHandler(fh) -keep_fds = [fh.stream.fileno()] - - -def main(): - logger.debug("Test") - -daemon = Daemonize(app="test_app", pid=pid, action=main, keep_fds=keep_fds) -daemon.start() -``` diff -Nru python-daemonize-2.3.1/README.rst python-daemonize-2.4.7/README.rst --- python-daemonize-2.3.1/README.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-daemonize-2.4.7/README.rst 2016-07-28 16:15:53.000000000 +0000 @@ -0,0 +1,96 @@ +daemonize +======================== + + +.. image:: https://readthedocs.org/projects/daemonize/badge/?version=latest + :target: http://daemonize.readthedocs.org/en/latest/?badge=latest + :alt: Latest version + +.. image:: https://img.shields.io/travis/thesharp/daemonize.svg + :target: http://travis-ci.org/thesharp/daemonize + :alt: Travis CI + +.. image:: https://img.shields.io/pypi/dm/daemonize.svg + :target: https://pypi.python.org/pypi/daemonize + :alt: PyPI montly downloads + +.. image:: https://img.shields.io/pypi/v/daemonize.svg + :target: https://pypi.python.org/pypi/daemonize + :alt: PyPI last version available + +.. image:: https://img.shields.io/pypi/l/daemonize.svg + :target: https://pypi.python.org/pypi/daemonize + :alt: PyPI license + + +**daemonize** is a library for writing system daemons in Python. It is +distributed under MIT license. Latest version can be downloaded from +`PyPI `__. Full documentation can +be found at +`ReadTheDocs `__. + +Dependencies +------------ + +It is tested under following Python versions: + +- 2.6 +- 2.7 +- 3.3 +- 3.4 +- 3.5 + +Installation +------------ + +You can install it from Python Package Index (PyPI): + +:: + + $ pip install daemonize + +Usage +----- + +.. code-block:: python + + from time import sleep + from daemonize import Daemonize + + pid = "/tmp/test.pid" + + + def main(): + while True: + sleep(5) + + daemon = Daemonize(app="test_app", pid=pid, action=main) + daemon.start() + +File descriptors +---------------- + +Daemonize object's constructor understands the optional argument +**keep\_fds** which contains a list of FDs which should not be closed. +For example: + +.. code-block:: python + + import logging + from daemonize import Daemonize + + pid = "/tmp/test.pid" + logger = logging.getLogger(__name__) + logger.setLevel(logging.DEBUG) + logger.propagate = False + fh = logging.FileHandler("/tmp/test.log", "w") + fh.setLevel(logging.DEBUG) + logger.addHandler(fh) + keep_fds = [fh.stream.fileno()] + + + def main(): + logger.debug("Test") + + daemon = Daemonize(app="test_app", pid=pid, action=main, keep_fds=keep_fds) + daemon.start() diff -Nru python-daemonize-2.3.1/setup.cfg python-daemonize-2.4.7/setup.cfg --- python-daemonize-2.3.1/setup.cfg 1970-01-01 00:00:00.000000000 +0000 +++ python-daemonize-2.4.7/setup.cfg 2016-07-28 16:15:53.000000000 +0000 @@ -0,0 +1,2 @@ +[bdist_wheel] +universal = 1 diff -Nru python-daemonize-2.3.1/setup.py python-daemonize-2.4.7/setup.py --- python-daemonize-2.3.1/setup.py 2014-05-28 18:13:57.000000000 +0000 +++ python-daemonize-2.4.7/setup.py 2016-07-28 16:15:53.000000000 +0000 @@ -1,10 +1,20 @@ #!/usr/bin/python +import re +import ast + from setuptools import setup, find_packages +_version_re = re.compile(r'__version__\s+=\s+(.*)') + + +with open('daemonize.py', 'rb') as f: + version = str(ast.literal_eval(_version_re.search( + f.read().decode('utf-8')).group(1))) + setup( name="daemonize", - version="2.3.1", + version=version, py_modules=["daemonize"], author="Ilya Otyutskiy", author_email="ilya.otyutskiy@icloud.com", @@ -19,10 +29,14 @@ "Operating System :: MacOS :: MacOS X", "Operating System :: POSIX :: Linux", "Operating System :: POSIX :: BSD :: FreeBSD", + "Operating System :: POSIX :: BSD :: OpenBSD", + "Operating System :: POSIX :: BSD :: NetBSD", "Programming Language :: Python", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", "Topic :: Software Development"] ) diff -Nru python-daemonize-2.3.1/tests/daemon_chdir.py python-daemonize-2.4.7/tests/daemon_chdir.py --- python-daemonize-2.3.1/tests/daemon_chdir.py 1970-01-01 00:00:00.000000000 +0000 +++ python-daemonize-2.4.7/tests/daemon_chdir.py 2016-07-28 16:15:53.000000000 +0000 @@ -0,0 +1,18 @@ +#!/usr/bin/env python + +from sys import argv + +from daemonize import Daemonize + +pid = argv[1] +working_dir = argv[2] +file_name = argv[3] + + +def main(): + with open(file_name, "w") as f: + f.write("test") + + +daemon = Daemonize(app="test_app", pid=pid, action=main, chdir=working_dir) +daemon.start() diff -Nru python-daemonize-2.3.1/tests/daemon_uid_gid_action.py python-daemonize-2.4.7/tests/daemon_uid_gid_action.py --- python-daemonize-2.3.1/tests/daemon_uid_gid_action.py 2014-05-28 18:13:57.000000000 +0000 +++ python-daemonize-2.4.7/tests/daemon_uid_gid_action.py 2016-07-28 16:15:53.000000000 +0000 @@ -1,6 +1,6 @@ #!/usr/bin/env python -from os import getuid, geteuid, getgid, getegid +from os import getuid, geteuid, getgid, getegid, path from sys import argv from time import sleep @@ -20,6 +20,8 @@ f.write(" ".join(map(str, uids + gids))) -daemon = Daemonize(app="test_app", pid=pid, action=main, user="nobody", group="nobody", +group = "nogroup" if path.exists("/etc/debian_version") else "nobody" + +daemon = Daemonize(app="test_app", pid=pid, action=main, user="nobody", group=group, privileged_action=priv) daemon.start() diff -Nru python-daemonize-2.3.1/tests/daemon_uid_gid.py python-daemonize-2.4.7/tests/daemon_uid_gid.py --- python-daemonize-2.3.1/tests/daemon_uid_gid.py 2014-05-28 18:13:57.000000000 +0000 +++ python-daemonize-2.4.7/tests/daemon_uid_gid.py 2016-07-28 16:15:53.000000000 +0000 @@ -1,6 +1,6 @@ #!/usr/bin/env python -from os import getuid, geteuid, getgid, getegid +from os import getuid, geteuid, getgid, getegid, path from sys import argv from time import sleep @@ -17,5 +17,7 @@ f.write(" ".join(map(str, uids + gids))) -daemon = Daemonize(app="test_app", pid=pid, action=main, user="nobody", group="nobody") +group = "nogroup" if path.exists("/etc/debian_version") else "nobody" + +daemon = Daemonize(app="test_app", pid=pid, action=main, user="nobody", group=group) daemon.start() diff -Nru python-daemonize-2.3.1/tests/test.py python-daemonize-2.4.7/tests/test.py --- python-daemonize-2.3.1/tests/test.py 2014-05-28 18:13:57.000000000 +0000 +++ python-daemonize-2.4.7/tests/test.py 2016-07-28 16:15:53.000000000 +0000 @@ -6,6 +6,7 @@ from tempfile import mkstemp from time import sleep +from os.path import split NOBODY_UID = pwd.getpwnam("nobody").pw_uid if os.path.exists("/etc/debian_version"): @@ -87,14 +88,14 @@ if os.getuid() != 0: return True - os.chown(self.pidfile, NOBODY_UID, NOBODY_GID) os.chown(self.logfile, NOBODY_UID, NOBODY_GID) os.system("python tests/daemon_uid_gid.py %s %s" % (self.pidfile, self.logfile)) - sleep(.1) + sleep(1) with open(self.logfile, "r") as f: self.assertEqual(f.read(), self.expected) + self.assertFalse(os.access(self.pidfile, os.F_OK)) def test_uid_gid_action(self): # Skip test if user is not root @@ -104,7 +105,7 @@ os.chown(self.pidfile, NOBODY_UID, NOBODY_GID) os.system("python tests/daemon_uid_gid_action.py %s %s" % (self.pidfile, self.logfile)) - sleep(.1) + sleep(1) with open(self.logfile, "r") as f: self.assertEqual(f.read(), self.expected) @@ -131,5 +132,23 @@ with open(self.logfile, "r") as contents: self.assertEqual(contents.read(), self.correct_log) + +class ChdirTest(unittest.TestCase): + def setUp(self): + self.pidfile = mkstemp()[1] + self.target = mkstemp()[1] + base, file = split(self.target) + + os.system("python tests/daemon_chdir.py %s %s %s" % (self.pidfile, base, file)) + sleep(1) + + def tearDown(self): + os.system("kill `cat %s`" % self.pidfile) + sleep(.1) + + def test_keep_fds(self): + log = open(self.target, "r").read() + self.assertEqual(log, "test") + if __name__ == '__main__': unittest.main() diff -Nru python-daemonize-2.3.1/.travis.yml python-daemonize-2.4.7/.travis.yml --- python-daemonize-2.3.1/.travis.yml 2014-05-28 18:13:57.000000000 +0000 +++ python-daemonize-2.4.7/.travis.yml 2016-07-28 16:15:53.000000000 +0000 @@ -4,8 +4,10 @@ - "2.7" - "3.3" - "3.4" -install: pip install . -script: nosetests + - "3.5" +install: sudo pip install nose sphinx sphinx_rtd_theme; sudo pip install . +script: sudo nosetests && sudo make docs notifications: webhooks: - - http://moriarty.thesharp.org:5000/travis/2c27baee8754c01522cf751c1ed393b1/ + - http://tg.thesharp.org:8888/travis +sudo: true