diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..468ee61 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,10 @@ +[run] +source = zc.zope3recipes +parallel = true +data_file = $COVERAGE_HOME/.coverage + +[paths] +source = + zc/ + .tox/*/lib/python*/site-packages/zc/ + .tox/pypy*/site-packages/zc/ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b744c06 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +*.py[co] +.tox/ +*.egg-info +.coverage +.installed.cfg +bin/ +eggs/ +develop-eggs/ +parts/ +.coverage* diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..3c6cd6b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,18 @@ +language: python +dist: xenial +python: + - 2.7 +install: + - pip install zope.testrunner coverage coveralls + - pip install -e '.[tests]' +script: + - export COVERAGE_HOME=$(pwd) + - export COVERAGE_PROCESS_START=$COVERAGE_HOME/.coveragerc + - coverage run -m zope.testrunner --test-path=. -vc +after_script: + - coverage combine + - coverage report -m + - coveralls +notifications: + email: false +cache: pip diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..80f0c26 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,3 @@ +include *.py +include buildout.cfg +recursive-include zc *.txt diff --git a/README.txt b/README.txt index b9bc870..dbd204a 100644 --- a/README.txt +++ b/README.txt @@ -20,6 +20,14 @@ Unfortunately, partial Windows support at this time. It works but it's alpha. Releases ******** +=================== +0.19.0 (unreleased) +=================== + +- Fix TypeError: () takes no arguments (1 given) on Windows + with zdaemon >= 3.0.0. + + =================== 0.18.0 (2013/02/05) =================== diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..7b99608 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,23 @@ +version: build-{build}-{branch} + +environment: + matrix: + # https://www.appveyor.com/docs/installed-software#python lists available + # versions + - PYTHON: "C:\\Python27" + +init: + - "echo %PYTHON%" + +install: + - "set PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%" + - python --version + # Upgrade virtualenv because the one in the Appveyor image is old and has an + # old bundled pip version that thinks 'zc.recipe.egg' is an egg. + - pip install -U virtualenv + - pip install tox + +build: off + +test_script: + - tox -e py diff --git a/setup.py b/setup.py index 00e1686..0bfa10f 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ # FOR A PARTICULAR PURPOSE. # ############################################################################## -name, version = "zc.zope3recipes", "0" +name, version = "zc.zope3recipes", "0.19.0.dev0" import os from setuptools import setup, find_packages @@ -58,7 +58,7 @@ def read(*rnames): ], }, extras_require = dict( - tests = ['zdaemon', 'zc.recipe.filestorage', 'PasteScript'], + tests=['zdaemon >= 3.0.0', 'zc.recipe.filestorage', 'PasteScript'], ), classifiers=[ "Development Status :: 5 - Production/Stable", diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..fc78c84 --- /dev/null +++ b/tox.ini @@ -0,0 +1,30 @@ +[tox] +envlist = py27 + +[testenv] +usedevelop = true +deps = + zope.testrunner +extras = + tests +commands = + zope-testrunner --test-path=. {posargs:-vc} + +[testenv:coverage] +basepython = python2.7 +deps = + {[testenv]deps} + coverage +commands = + coverage run -m zope.testrunner --test-path=. {posargs:-vc} + coverage combine + coverage report -m +setenv = + COVERAGE_HOME={toxinidir} + COVERAGE_PROCESS_START={toxinidir}/.coveragerc + +[testenv:py] +platform = win32 +deps = + {[testenv]deps} + pypiwin32 diff --git a/zc/zope3recipes/README.txt b/zc/zope3recipes/README.txt index a295117..34ed945 100644 --- a/zc/zope3recipes/README.txt +++ b/zc/zope3recipes/README.txt @@ -109,7 +109,7 @@ in ``sys.path``. Similarly debugzope script is also changed: sys.path[0:0] = [ '/sample-buildout/demo2', '/sample-buildout/demo1', - '/zope3recipes', + '/zc.zope3recipes', ] import zope.app.twisted.main @@ -174,7 +174,7 @@ before server is started: sys.path[0:0] = [ '/sample-buildout/demo2', '/sample-buildout/demo1', - '/zope3recipes', + '/zc.zope3recipes', ] print "Starting application server." @@ -224,7 +224,7 @@ Now, Let's run the buildout and see what we get: sys.path[0:0] = [ '/sample-buildout/demo2', '/sample-buildout/demo1', - '/zope3recipes', + '/zc.zope3recipes', ] print "Starting debugging interaction." @@ -289,7 +289,7 @@ Now, Let's run the buildout and see what we get: sys.path[0:0] = [ '/sample-buildout/demo2', '/sample-buildout/demo1', - '/zope3recipes', + '/zc.zope3recipes', ] import zope.app.twisted.main @@ -380,7 +380,7 @@ Similarly, debugzope script has relative paths. sys.path[0:0] = [ join(base, 'demo2'), join(base, 'demo1'), - '/zope3recipes', + '/zc.zope3recipes', ] import zope.app.twisted.main @@ -542,7 +542,7 @@ variables available as global variables. '/sample-buildout/demo2', '/sample-buildout/demo1', '/zope3/src', - '/zope3recipes', + '/zc.zope3recipes', ] import zope.app.twisted.main @@ -682,7 +682,7 @@ The debugzope script has also been modified to take this into account. '/sample-buildout/demo2', '/sample-buildout/demo1', '/zope3/src', - '/zope3recipes', + '/zc.zope3recipes', ] import zope.app.server.main @@ -776,7 +776,7 @@ The debugzope script also has relative paths. join(base, 'demo2'), join(base, 'demo1'), '/zope3/src', - '/zope3recipes', + '/zc.zope3recipes', ] import zope.app.server.main @@ -1559,10 +1559,8 @@ in the buildout bin directory: import sys sys.path[0:0] = [ - '/sample-buildout/eggs/zdaemon-2.0-py2.4.egg', - '/sample-buildout/eggs/setuptools-0.6-py2.4.egg', - '/sample-buildout/eggs/ZConfig-2.3-py2.4.egg', - '/zope3recipes', + '/site-packages', + '/zc.zope3recipes', ] import zc.zope3recipes.ctl @@ -1878,7 +1876,7 @@ rc-directory installed. logrotate-directory - The name ot the directory where logrotate configuration files should be + The name of the directory where logrotate configuration files should be installed. user @@ -2449,10 +2447,8 @@ in a buildout configuration. import sys sys.path[0:0] = [ - join(base, 'eggs/zdaemon-pyN.N.egg'), - join(base, 'eggs/setuptools-pyN.N.egg'), - join(base, 'eggs/ZConfig-pyN.N.egg'), - '/zope3recipes', + '/site-packages', + '/zc.zope3recipes', ] import zc.zope3recipes.ctl @@ -3149,14 +3145,10 @@ paste-based instance start scripts. import sys sys.path[0:0] = [ - '/sample-buildout/demo2', - '/sample-buildout/eggs/PasteScript-1.7.4.2-py2.6.egg', - '/sample-buildout/eggs/setuptools-0.6c12dev_r88846-py2.6.egg', - '/sample-buildout/eggs/PasteDeploy-1.5.0-py2.6.egg', - '/sample-buildout/eggs/Paste-1.7.5.1-py2.6.egg', - '/sample-buildout/demo1', - ] - + '/sample-buildout/demo2', + '/sample-buildout/demo1', + '/site-packages', + ] import paste.script.command diff --git a/zc/zope3recipes/WINDOWS.txt b/zc/zope3recipes/WINDOWS.txt index eb65b24..b90eee1 100644 --- a/zc/zope3recipes/WINDOWS.txt +++ b/zc/zope3recipes/WINDOWS.txt @@ -79,7 +79,7 @@ The runzope script runs the Web server: import zope.app.twisted.main if __name__ == '__main__': - zope.app.twisted.main.main() + sys.exit(zope.app.twisted.main.main()) Here, unlike the above example the location path is not included in sys.path . Similarly debugzope script is also changed: @@ -91,7 +91,7 @@ in sys.path . Similarly debugzope script is also changed: sys.path[0:0] = [ '/sample-buildout/demo2', '/sample-buildout/demo1', - '/zope3recipes', + '/zc.zope3recipes', ] import zope.app.twisted.main @@ -100,7 +100,7 @@ in sys.path . Similarly debugzope script is also changed: import zc.zope3recipes.debugzope if __name__ == '__main__': - zc.zope3recipes.debugzope.debug(main_module=zope.app.twisted.main) + sys.exit(zc.zope3recipes.debugzope.debug(main_module=zope.app.twisted.main)) Building Zope 3 Applications (from Zope 3 checkouts/tarballs) @@ -219,7 +219,7 @@ The runzope script runs the Web server: import zope.app.twisted.main if __name__ == '__main__': - zope.app.twisted.main.main() + sys.exit(zope.app.twisted.main.main()) It includes in it's path the eggs we specified in the configuration file, along with their dependencies. Note that we haven't specified a @@ -249,7 +249,7 @@ variables available as global variables. '/sample-buildout/demo2', '/sample-buildout/demo1', '/zope3/src', - '/zope3recipes', + '/zc.zope3recipes', ] import zope.app.twisted.main @@ -258,7 +258,7 @@ variables available as global variables. import zc.zope3recipes.debugzope if __name__ == '__main__': - zc.zope3recipes.debugzope.debug(main_module=zope.app.twisted.main) + sys.exit(zc.zope3recipes.debugzope.debug(main_module=zope.app.twisted.main)) Note that the runzope shown above uses the default, twisted-based server components. It's possible to specify which set of server @@ -321,7 +321,7 @@ The runzope script generated is identical to what we saw before: import zope.app.twisted.main if __name__ == '__main__': - zope.app.twisted.main.main() + sys.exit(zope.app.twisted.main.main()) We can also specify the ZServer servers explicitly: @@ -377,7 +377,7 @@ different package this time: import zope.app.server.main if __name__ == '__main__': - zope.app.server.main.main() + sys.exit(zope.app.server.main.main()) The debugzope script has also been modified to take this into account. @@ -389,7 +389,7 @@ The debugzope script has also been modified to take this into account. '/sample-buildout/demo2', '/sample-buildout/demo1', '/zope3/src', - '/zope3recipes', + '/zc.zope3recipes', ] import zope.app.server.main @@ -398,7 +398,7 @@ The debugzope script has also been modified to take this into account. import zc.zope3recipes.debugzope if __name__ == '__main__': - zc.zope3recipes.debugzope.debug(main_module=zope.app.server.main) + sys.exit(zc.zope3recipes.debugzope.debug(main_module=zope.app.server.main)) Legacy Functional Testing Support @@ -1169,21 +1169,19 @@ in the buildout bin directory: import sys sys.path[0:0] = [ - '/sample-buildout/eggs/zdaemon-2.0-py2.4.egg', - '/sample-buildout/eggs/setuptools-0.6-py2.4.egg', - '/sample-buildout/eggs/ZConfig-2.3-py2.4.egg', - '/zope3recipes', + '/site-packages', + '/zc.zope3recipes', ] import zc.zope3recipes.winctl if __name__ == '__main__': - zc.zope3recipes.winctl.main([ + sys.exit(zc.zope3recipes.winctl.main([ '/sample-buildout/parts/myapp/debugzope', '/sample-buildout/parts/instance/zope.conf', '-C', '/sample-buildout/parts/instance/zdaemon.conf', ]+sys.argv[1:] - ) + )) Some configuration sections can include a key multiple times; the ZEO client section works this way. When a key is given multiple times, @@ -1321,6 +1319,10 @@ rc-directory The name of the directory where run-control scripts should be installed. +logrotate-directory + The name of the directory where logrotate configuration files should be + installed. + user The name of a user that processes should run as. @@ -1333,6 +1335,7 @@ create a faux installation root: >>> mkdir(root, 'etc') >>> mkdir(root, 'etc', 'myapp-run') >>> mkdir(root, 'etc', 'init.d') + >>> mkdir(root, 'etc', 'logrotate.d') >>> write('buildout.cfg', ... ''' @@ -1372,6 +1375,7 @@ create a faux installation root: ... [myapp-run] ... etc-directory = %(root)s/etc/myapp-run ... rc-directory = %(root)s/etc/init.d + ... logrotate-directory = %(root)s/etc/logrotate.d ... log-directory = %(root)s/var/log/myapp-run ... run-directory = %(root)s/var/run/myapp-run ... user = zope @@ -1422,6 +1426,12 @@ The control script is in the init.d directory: Note that the deployment name is added as a prefix of the control script name. +The logrotate file is in the logrotate.d directory: + + >>> ls(root, 'etc', 'logrotate.d') + - myapp-run-instance + + The configuration files have changed to reflect the deployment locations: @@ -1468,6 +1478,16 @@ locations: + >>> cat(root, 'etc', 'logrotate.d', 'myapp-run-instance') + /root/var/log/myapp-run/instance-z3.log { + rotate 5 + weekly + postrotate + /root/etc/init.d/myapp-run-instance reopen_transcript + endscript + } + + Defining multiple similar instances ----------------------------------- @@ -1522,6 +1542,7 @@ Let's update our buildout to add a new instance: ... [myapp-run] ... etc-directory = %(root)s/etc/myapp-run ... rc-directory = %(root)s/etc/init.d + ... logrotate-directory = %(root)s/etc/logrotate.d ... log-directory = %(root)s/var/log/myapp-run ... run-directory = %(root)s/var/run/myapp-run ... user = zope diff --git a/zc/zope3recipes/tests.py b/zc/zope3recipes/tests.py index 63ee8a3..2988c5f 100644 --- a/zc/zope3recipes/tests.py +++ b/zc/zope3recipes/tests.py @@ -12,12 +12,15 @@ # ############################################################################## -import re, sys, os +import doctest +import os +import re +import sys +import unittest import zc.buildout.testing +from zope.testing import renormalizing -import unittest -from zope.testing import doctest, renormalizing def ls_optional(dir, ignore=(), *subs): if subs: @@ -35,6 +38,7 @@ def ls_optional(dir, ignore=(), *subs): print '- ', print name + def test_ctl(): """ The ctl script is an extended version of zdaemon that provides an @@ -236,40 +240,88 @@ def setUp(test): "\(maybe misspelled\?\)" "\n" ), ''), - (re.compile("""['"][^\n"']+zope3recipes[^\n"']*['"],"""), - "'/zope3recipes',"), + # Windows + (re.compile(r'\r\n'), '\n'), + # this directory + (re.compile(r"""['"][^\n"']+zc.zope3recipes['"],"""), + "'/zc.zope3recipes',"), + # welp, when we do things like `tox -e coverage`, everything's in + # .tox/coverage/lib/pythonX.Y/site-packages and that's what gets added to + # sys.path in the generated scripts + (re.compile("""['"][^\n"']+site-packages['"],"""), + "'/site-packages',"), (re.compile('#![^\n]+\n'), ''), - (re.compile('-\S+-py\d[.]\d(-\S+)?.egg'), + (re.compile('-[^-]+-py\d[.]\d(-\S+)?.egg'), '-pyN.N.egg', ), # Turn "distribute" into "setuptools" so the tests can pass with either: (re.compile(r'\bdistribute-pyN\.N\.egg'), 'setuptools-pyN.N.egg', ), - ]) + # Sometimes buildout decides to also install six + (re.compile( + r"Getting distribution for 'six'\.\nGot six [0-9.]+\.\n" + ), ''), + # Running the tests under coverage changes the output ordering! This makes + # no sense! + (re.compile( + r"( *'/zope3recipes',\n)( *'/sample-buildout/demo1',\n)" + ), r'\2\1'), + # Running the tests with buildout + bin/test adds ZConfig and zdaemon + # eggs to sys.path of generated tests. Running the tests with tox does + # not (because ZConfig and zdaemon are already in .../site-packages) + (re.compile( + r" *'/sample-buildout/eggs/(ZConfig|zdaemon)-pyN.N.egg',\n" + ), ''), + (re.compile( + r" *join\(base, 'eggs/(ZConfig|zdaemon)-pyN.N.egg'\),\n" + ), ''), + (re.compile( + r"( *'/sample-buildout/eggs/(PasteScript|six|PasteDeploy|Paste)-pyN.N.egg',\n)+" + ), " '/site-packages',\n"), + # tox -e coverage does this! I've no idea why! + (re.compile( + r"Uninstalling myapp.\n" + r"(Updating database.\n|Installing database.\n|Uninstalling database.\n|)" + r"Installing myapp.\n" + r"(Generated script '/sample-buildout/parts/myapp/[^']+'\.\n)*", + ), "\\1Updating myapp.\n"), + (re.compile( + r"Uninstalling instance.\n" + r"(Updating myapp.\n|)" + r"Installing instance.\n" + r"(Generated script '/sample-buildout/bin/[^']+'\.\n)*", + ), "\\1Updating instance.\n"), +]) def test_suite(): suite = unittest.TestSuite() + optionflags = ( + doctest.NORMALIZE_WHITESPACE + | doctest.ELLIPSIS + | doctest.REPORT_NDIFF + ) if sys.platform[:3].lower() == "win": suite.addTest(doctest.DocFileSuite('WINDOWS.txt', setUp=setUp, tearDown=zc.buildout.testing.buildoutTearDown, checker=checker, - optionflags = doctest.NORMALIZE_WHITESPACE+doctest.ELLIPSIS)) + optionflags=optionflags)) else: suite.addTest(doctest.DocTestSuite( setUp=setUp, tearDown=zc.buildout.testing.buildoutTearDown, checker=checker, - optionflags = doctest.NORMALIZE_WHITESPACE+doctest.ELLIPSIS)) + optionflags=optionflags)) suite.addTest(doctest.DocFileSuite('README.txt', setUp=setUp, tearDown=zc.buildout.testing.buildoutTearDown, checker=checker, - optionflags = doctest.NORMALIZE_WHITESPACE+doctest.ELLIPSIS)) + optionflags=optionflags)) return suite + if __name__ == '__main__': unittest.main(defaultTest='test_suite') diff --git a/zc/zope3recipes/winctl.py b/zc/zope3recipes/winctl.py index 30b31d8..b876eae 100644 --- a/zc/zope3recipes/winctl.py +++ b/zc/zope3recipes/winctl.py @@ -211,7 +211,7 @@ def do_debug(self, arg): self.proc = Popen(program) self.zd_pid = self.proc.pid self.zd_up = 1 - self.awhile(lambda: self.zd_pid, + self.awhile(lambda n: self.zd_pid, "Zope3 started in debug mode, pid=%(zd_pid)d") def help_debug(self): @@ -261,7 +261,7 @@ def do_stop(self, arg): self.zd_up = 0 self.zd_pid = 0 cpid = win32process.GetCurrentProcessId() - self.awhile(lambda: not getChildrenPidsOfPid(cpid), "Zope3 stopped") + self.awhile(lambda n: not getChildrenPidsOfPid(cpid), "Zope3 stopped") def do_kill(self, arg): self.do_stop(arg) @@ -273,7 +273,7 @@ def do_restart(self, arg): self.do_start(arg) else: self.do_start(arg) - self.awhile(lambda: self.zd_pid not in (0, pid), + self.awhile(lambda n: self.zd_pid not in (0, pid), "Zope3 restarted, pid=%(zd_pid)d") def show_options(self): @@ -295,7 +295,7 @@ def do_start(self, arg): self.proc = Popen(program) self.zd_pid = self.proc.pid self.zd_up = 1 - self.awhile(lambda: self.zd_pid, + self.awhile(lambda n: self.zd_pid, "Zope3 started, pid=%(zd_pid)d") def do_fg(self, arg):