Package: sauna.reload
sauna.reload: so that you can finish your Plone development today and relax in
sauna after calling it a dayIntroductionUser commentsInstallationPrerequisitementsInstalling buildout configurationOSX notesUbuntu / Debian / Linux notesUsage: start Plone in reload enabled mannerManual reloadDebugging withsauna.reloadBackgroundEventsLimitationsDoes not handle dependenciesForces loading all dependenciesDoes not work with core packagesProduct installation order is alteredTroubleshootingMy code does not reload properlyI want to exclude mymeta.zcmlfrom reloadI want to exclude ALLmeta.zcmlfrom reloadsauna.reload is not active - nothing printed on consoleSourceCreditsChangelog0.5.5 (2016-02-24)0.5.4 (2016-02-24)0.5.3 (2014-10-19)0.5.2 (2014-10-18)0.5.1 (2013-02-20)0.5.0 (2012-12-28)0.4.3 (2012-04-25)0.4.2 (2012-04-24)0.4.0 (2012-04-22)0.3.3 (2011-10-17)0.3.2 (2011-08-21)0.3.1 – 2011-08-190.3.0 (2011-08-12)0.2.1 (2011-08-03)0.2.0 (2011-08-04)0.1.1 (2011-08-03)0.1.0 (2011-08-03)Introductionsauna.reloadis a developer tool which restarts Plone and reloads your changed source
code every time you save a file. The restart is optimized for speed
and happens much faster than a normal start up process.Edit your codeSaveGo to a browser and hitRefresh➔ your latest changes are activeIt greatly simplifies your Plone development workflow and gives back the
agility of Python.It works with any code.sauna.reloadworks on OSX and Linux with Plone 4.0 and 4.1. In theory
works on Windows, but no one has looked into that yet.User comments“I don’t want to use sauna.reload as I can knit a row while I restart …”“no more do I start a 5 minute cigarette every time Plone restarts for 30
seconds… ok wait, this kind of joy leads to poetry, I’m gonna stop here.”InstallationHere are brief installation instructions.PrerequisitementsIn order to take the advantage ofsauna.reloadYou know how to develop your own Plone add-ons and basics of buildout folder
structureYou know UNIX command line basicsYou know how to run buildoutYou are running Linux or OSX operating systemNo knowledge for warming up sauna is needed in order to use this product.Installing buildout configurationThe recommended installation configuration is to use ZEO server + 1 client for the development.
This method is valid forPlone 4.1 and higher. You can usesauna.reloadwithout separate ZEO database server, usinginstancecommand,
butin this case you’ll risk database corruption on restarts.Below is the recommended approach how to enablesauna.reloadfor your
development environment. However, since this product is only for development
use the data loss should not be a big deal.Addsauna.reloadto yourbuildout.cfgfile:buildout.cfg:[buildout]
eggs +=
    sauna.reload

# This section is either client1 / instance depending
# on your buildout
[instance]
zope-conf-additional = %import sauna.reloadOSX notesIf you are using vim (or macvim) on OSX, you must disable vim’s writebackups
to allow WatchDog to see your modifications
(otherwise vim will technicallyj create a new file on each save and WatchDog
doesn’t report the modification back tosauna.reload).So, Add the following to the end of your.vimrc:set noswapfile
set nobackup
set nowritebackupSimilar issues have been reported with some other OSX-editors.
Tips and fixes for these are welcome.Ubuntu / Debian / Linux notesYou might need to raise your open filesulimitif you are operating on the
large set of files, both hard and soft limit.http://posidev.com/blog/2009/06/04/set-ulimit-parameters-on-ubuntu/104000 is a known good value.If yourulimitis too low you’ll get very misleadingOSError: No space left
on device.Usage: start Plone in reload enabled mannerTo start Plone with reload functionality you need
to give special environment variableRELOAD_PATHfor your client1 command:# Start database server
bin/zeoserver start

# Start Plone with reload enabled
RELOAD_PATH=src bin/client1 fgOr if you want to optimize load speed you can directly specify only some of
your development products:RELOAD_PATH=src/my.product:src/my.another.product bin/client1 fgWarningIf other products depend on your product, e.g CMFPlone
dependencies, sauna.reload does not kick in early enough and the reload does
not work.When reload is active you should see something like this in your console
when Zope starts up:2011-08-10 13:28:59 INFO sauna.reload Starting file monitor on /Users/moo/code/x/plone4/src
2011-08-10 13:29:02 INFO sauna.reload We saved at least 29.8229699135 seconds from boot up time
2011-08-10 13:29:02 INFO sauna.reload Overview available at: http://127.0.0.1:8080/@@saunareload
2011-08-10 13:29:02 INFO sauna.reload Fork loop starting on process 14607
2011-08-10 13:29:02 INFO sauna.reload Booted up new new child in 0.104816913605 seconds. Pid 14608… and when you save some file insrcfolder:2011-08-10 13:29:41 INFO SignalHandler Caught signal SIGINT
2011-08-10 13:29:41 INFO Z2 Shutting down
2011-08-10 13:29:42 INFO SignalHandler Caught signal SIGCHLD
2011-08-10 13:29:42 INFO sauna.reload Booted up new new child in 0.123936891556 seconds. Pid 14609CTRL+C should terminate Zope normally. There might be stil some kinks and error
messages with shutdown.NoteYour reloadable eggs must be included using z3c.autoinclude
mechanism.Only eggs loaded throughz3c.autoincludecan be reloaded.
Make sure you don’t use buildout.cfgzcml =directive for your eggs orsauna.reloadsilently ignores changes.Manual reloadThere is also a view on Zope2 root from which it is possible to manually reload
code:http://127.0.0.1:8080/@@saunareloadDebugging withsauna.reloadRegularimport pdb; pdb.set_trace()will work just fine withsauna.reloadand usingipdbas a drop-in forpdbwill work fine as well.
When reloads happen while in either pdb or ipdb, the debugger will get
killed.
To avoid losing your terminal echo, because of reload unexpectedly
killing your debugger, you may add the following to your~/.pdbrc:import termios, sys
term_fd = sys.stdin.fileno()
term_echo = termios.tcgetattr(term_fd)
term_echo[3] = term_echo[3] | termios.ECHO
term_result = termios.tcsetattr(term_fd, termios.TCSADRAIN, term_echo)As ipdb extends pdb, this configuration file will also work to restore the
terminal echo.sauna.reloadalso should work nicely withPdbTextMateSupportandPdbSublimeTextSupport. Unfortunately, we
haven’t seen it working withvimpdbyet.Backgroundsauna.reloadis an attempt to recreateplone.reloadwithout the issues
it has. Like being unable to reload new grokked views or portlet code. This
project was started on Plone Sauna Sprint 2011. There for the name,sauna.reload.sauna.reloaddoes reloading by using a fork loop. So actually it does not
reload the code, but restarts small part of Zope2. That’s why it can it reload
stuffplone.reloadcannot.It does following on Zope2 startup:Defers loading of your development packages by hooking into PEP 302 loader
and changing theirz3c.autoincludetarget module (and monkeypatching
fiveconfigure/metaconfigure for legacy packages).Starts a watcher thread which monitors changes in your development py-filesStops loading of Zope2 inzope.processlifetime.IProcessStartingevent by
stepping into a infinite loop; Just before this, tries to load all
non-developed dependencies of your development packages (resolved byz3c.autoinclude)It forks a new child and lets it pass the loopLoads all your development packages invokingz3c.autoinclude(and
fiveconfigure/metaconfigure for legacy packages). This is fast!And now every time when the watcher thread detects a change in development
files it will signal the child to shutdown and the child will signal
the parent to fork a new child when it is just about to close itselfJust before dying, the child savesData.fs.indexto help the new child
to see the changes in ZODB (by loading the saved index)GOTO 4Internallysauna.reloadusesWatchDogPython component for monitoring file-system change events.See alsoRuby guys on fork trick.EventsNoteThe following concerns you only if your code needs to react specially
to reloads (clear caches, etc.)sauna.reloademits couple of events during reloading.sauna.reload.events.INewChildForkedEmited immediately after new process is forked. No development packages have
been yet installed.  Useful if you want to do something before your code gets
loaded.  Note that you cannot listen this event on a package that is marked
for reloading as it is not yet installed when this is fired.sauna.reload.events.INewChildIsReadyEmitted when all the development packages has been installed to the new
forked child.  Useful for notifications etc.Limitationssauna.reloadsupports only Plone >= 4.0 for FileStorage and Plone >= 4.1
for ZEO ClientStorage.Does not handle dependenciessauna.reloadhas a major pitfall. Because it depends on deferring loading
of packages to be watched and reloaded, also every package depending on those
packages should be defined to be reloaded (inRELOAD_PATH). Andsauna.reloaddoesn’t resolve those dependencies automatically!Forces loading all dependenciesAn another potential troublemaker is thatsauna.reloadperforms implicit<includeDependenciespackage="."/>for every package inRELOAD_PATH(to preload dependencies for those packages to speed up the reload).This may break up some packages.Does not work with core packagesWe are sorry thatsauna.reloadmay not work for everyone. For example,
reloading of core Plone packages could be tricky, if not impossible, because
many of them are explicitly included byconfigure.zcmlof CMFPlone and are
not usingz3c.autoincludeat all. You would have to remove the dependency
from CMFPlone for development to make it work…Product installation order is alteredAlso because the product installation order is altered (by all the above) you
may find some issue if your product does something funky on installation or at
import time.Please report any other issues atGithub issue tracker.TroubleshootingReport all issues onGitHub.My code does not reload properlyYou’ll see reload process going on in the terminal, but your code is still not
loaded.You should see following warnings with zcml-paths from your products:2011-08-13 09:38:12 ERROR sauna.reload.child Cannot reload
src/sauna.reload/sauna/reload/configure.zcml.Make sure your code is hooked into Plone throughz3c.autoincludeand NOT
using explicitzcml = directivein buildout.cfg.Retrofit your eggs with autoinclude support if neededRemove zcml = lines for your eggs in buildout.cfgRerun buildout (remember bin/buildout -c development.cfg)Restart Plone with sauna.reload enabledI want to exclude mymeta.zcmlfrom reloadIt’s possible to manually exclude configuration files from reloading by forcing
them to be loaded before forkloop in a customsite.zcml. Be aware, that
whensite-zcmloption is used,zope2instanceignoreszcmlandzcml-additionaloptions.Define a customsite.zcmlin yourbuildout.cfgwith:[instance]
recipe = plone.recipe.zope2instance
...
site-zcml =
  <configure xmlns="http://namespaces.zope.org/zope"
             xmlns:meta="http://namespaces.zope.org/meta"
             xmlns:five="http://namespaces.zope.org/five">
    <include package="Products.Five" />
    <meta:redefinePermission from="zope2.Public" to="zope.Public" />
    <five:loadProducts file="meta.zcml"/>

    <!-- Add include for your package's meta.zcml here: -->
    <include package="my.product" file="meta.zcml" />

    <five:loadProducts />
    <five:loadProductsOverrides />
    <securityPolicy component="Products.Five.security.FiveSecurityPolicy" />
  </configure>I want to exclude ALLmeta.zcmlfrom reloadSure. See the tip above and use the snippet below instead:[instance]
recipe = plone.recipe.zope2instance
...
site-zcml =
  <configure xmlns="http://namespaces.zope.org/zope"
             xmlns:meta="http://namespaces.zope.org/meta"
             xmlns:five="http://namespaces.zope.org/five">
    <include package="Products.Five" />
    <meta:redefinePermission from="zope2.Public" to="zope.Public" />
    <five:loadProducts file="meta.zcml"/>

    <!-- Add autoinclude-directive for deferred meta.zcml here: -->
    <includePlugins package="sauna.reload" file="meta.zcml" />

    <five:loadProducts />
    <five:loadProductsOverrides />
    <securityPolicy component="Products.Five.security.FiveSecurityPolicy" />
  </configure>sauna.reload is not active - nothing printed on consoleCheck that your buildout.cfg includeszope-conf-additionalline.If using separatedevelopment.cfgmake sure you run your buildout using
it:bin/buildout -c development.cfgSourceOnGitHub.CreditsEsa-Matti Suuronen [esa-matti aet suuronen.org]Asko Soukka [asko.soukka aet iki.fi]Mikko Ohtamaa (idea, doccing)Vilmos Somogyi (logo). The logo was originally the logo of Sauna Sprint 2011
and it was created by Vilmos Somogyi.Martijn Pieters for teaching us PEP 302 -loader trick at Sauna Sprint 2011.Yesudeep Mangalapillyfor creatingWatchDogcomponent and providing support for Sauna Sprint team using itThanks to all happy hackers on Sauna Sprint 2011!300 kg of beer was consumed to create this package (at least). Also several
kilos of firewood, one axe, one chainsaw and one boat.We still need testers and contributors. You are very welcome!Changelog0.5.5 (2016-02-24)Add another workaround for watchdog raising annoying KeyErrors
[datakurre]0.5.4 (2016-02-24)Add workaround for watchdog raising annoying KeyErrors
[datakurre]0.5.3 (2014-10-19)Fix issue where in Zope version >= 2.13.19 the storage is explicitly closed
on shutdown. This caused an attribute error on reload, since the _rpc_mgr was
None. Test for is_connected before closing connection and cache.
[sunew]0.5.2 (2014-10-18)Log ‘cannot reload’ as warning instead of error to avoid triggering
postmortem debugging
[sunew]0.5.1 (2013-02-20)Fix IOError when sauna.reload is imported for a forked process
[datakurre]0.5.0 (2012-12-28)Prepopulate platform.uname, before it gets lost in the stack. All calls using
platform.uname() values would fail with an IOError(10).
[esteele]Fixed reloadings of Products-namespace eggs on Plone 4.1 and Zope 2.13
[miohtama]Log out the reason what killed the child
[miohtama]0.4.3 (2012-04-25)Updated README about ZEO-client support to be limited to Plone >= 4.1.0.4.2 (2012-04-24)Fixed BlogStorage-support (regression from 0.3.3).
[datakurre]0.4.0 (2012-04-22)Added log-messages about successfully reloaded configuration files.
Closeshttps://github.com/epeli/sauna.reload/issues/11[datakurre]Added support for reloading a ZEO-client on Plone >= 4.1.
Fixeshttps://github.com/collective/sauna.reload/issues/1[datakurre]Added support top.a.themingpluginswhenp.a.themingis installed.
Fixeshttps://github.com/epeli/sauna.reload/issues/15[datakurre]Fixed an issue ofzope2.Publicnot mapped tozope.Publicwhen confiuring
products during reload.
Fixeshttps://github.com/collective/sauna.reload/issues/2[datakurre]Fixed to depend onwatchdog>= 0.6.0 to support OSXout-of-the-box.
[datakurre]0.3.3 (2011-10-17)Fixed an issue in initializing more than one reloaded Archetype products.0.3.2 (2011-08-21)Fixed to work better with PdbSublimeText/TextMateSupport.README-updates (mainly for exluding zcmls from reload).0.3.1 – 2011-08-19Support for Five-initialized products (e.g. Archetypes) on Plone 4.1.Licensed under ZPL.0.3.0 (2011-08-12)Support Plone 4.1Heavily edited readme [miohtama]Show nice error log message if product installation failed to defer ie. is
not reloadable.0.2.1 (2011-08-03)Add INewChildIsReady event and move INewChildForked eventRemove overly used prints and use loggingCan now reload __init__.py from package root0.2.0 (2011-08-04)Support for Five-initialized products (e.g. Archetypes).Browser View for manual reloadingEmit INewChildForked eventsMany bug fixes0.1.1 (2011-08-03)Added missing egg description.Added forgotten reload for localizations.Prefixed commands in README with $.0.1.0 (2011-08-03)First experimental release.