Date post: | 29-Nov-2014 |
Category: |
Technology |
Upload: | clayton-parker |
View: | 950 times |
Download: | 1 times |
Clayton Parker | Senior Developer
Using Buildout, GenericSetup and a Policy Package to Rule the World
PLONE SYMPOSIUM EAST 2012
Who Am I
PLONE SYMPOSIUM EAST 2012What will we learn?
• Policy Package
• GenericSetup
• Plone Site Buildout Recipe
http://github.com/sixfeetup
Demo
Realization• Repeatable environments
• Fewer commands
• Repeatable product installation
PLONE SYMPOSIUM EAST 2012
PLONE SYMPOSIUM EAST 2012Human Err0r
“Hey Bob, did you run the fizzbang.widget profile on production”
“I think so, Doug”
“Do you know why the client is yelling at me right now?”
“Maybe I didn’t, let me fix that real quick”
Policy Package
PLONE SYMPOSIUM EAST 2012Create the package*
$ cd path/to/buildout/src$ zopeskel sfu_policy pse12.policy$ cd pse12.policy.. git init / add / etc ...
* This example uses sixieskel for brevity, you might use the “plone” template
PLONE SYMPOSIUM EAST 2012Package layout!"" setup.py#"" src #"" pse12 !"" __init__.py #"" policy !"" __init__.py !"" configure.zcml !"" profiles % !"" default % % #"" metadata.xml % #"" initial % #"" metadata.xml !"" setuphandlers.py !"" upgrades.py #"" upgrades.zcml
PLONE SYMPOSIUM EAST 2012Add to buildout
[buildout]extensions = mr.developerauto-checkout = Trueparts = instance
[sources]pse12.policy = git <git url here>
[instance]eggs = pse12.policy
PLONE SYMPOSIUM EAST 2012Dependencies
# pse12.policy/setup.pyinstall_requires=[ 'setuptools', 'Plone', 'Pillow', 'plone.app.caching',],
PLONE SYMPOSIUM EAST 2012ZCML# pse12.policy setup.pyentry_points="""[z3c.autoinclude.plugin]target = plone""",
<!-- pse12.policy configure.zcml --><includePlugins package="." /><includeDependencies package="." />
Generic Setup
PLONE SYMPOSIUM EAST 2012Default profile
<!-- pse12.policy configure.zcml --><genericsetup:registerProfile name="default" title="pse12.policy (default)" directory="profiles/default" description="Installation profile for pse12.policy" provides="Products.GenericSetup.interfaces.EXTENSION" />
PLONE SYMPOSIUM EAST 2012Initial profile
<!-- pse12.policy configure.zcml --><genericsetup:registerProfile name="initial" title="pse12.policy (initial)" directory="profiles/initial" description="Initial profile for pse12.policy" provides="Products.GenericSetup.interfaces.EXTENSION" />
PLONE SYMPOSIUM EAST 2012Metadata
<?xml version="1.0"?><metadata> <version>001</version> <dependencies>...</dependencies></metadata>
Add-ons
PLONE SYMPOSIUM EAST 2012Package
# Inside setup.pyinstall_requires=[ ... ‘plonetheme.transition’,],
PLONE SYMPOSIUM EAST 2012Package
<?xml version="1.0"?>
<!-- pse12.policy metadata.xml --><metadata> <version>001</version> <dependencies> <dependency>profile-plone.app.theming:default</dependency> </dependencies></metadata>
PLONE SYMPOSIUM EAST 2012Package
PLONE SYMPOSIUM EAST 2012Package# profiles/default/registry.xml<registry> <record field="enabled" interface="plone.app.theming.interfaces.IThemeSettings" name="plone.app.theming.interfaces.IThemeSettings.enabled"> <field type="plone.registry.field.Bool"> <default>False</default> <description>enable_theme_globally</description> <title>enabled</title> </field> <value>True</value> </record> <record field="absolutePrefix" interface="plone.app.theming.interfaces.IThemeSettings" name="plone.app.theming.interfaces.IThemeSettings.absolutePrefix"> <field type="plone.registry.field.TextLine"> <description>convert_relative_url</description> <required>False</required> <title>absolute_url_prefix</title> </field> <value>/++theme++plonetheme.transition</value> </record> <record field="currentTheme" interface="plone.app.theming.interfaces.IThemeSettings" name="plone.app.theming.interfaces.IThemeSettings.currentTheme"> <field type="plone.registry.field.TextLine"> <description>current_theme_description</description> <title>current_theme</title> </field> <value>plonetheme.transition</value> </record> <record field="rules" interface="plone.app.theming.interfaces.IThemeSettings" name="plone.app.theming.interfaces.IThemeSettings.rules"> <field type="plone.registry.field.TextLine"> <description>rules_file_path</description> <required>False</required> <title>rules_file</title> </field> <value>/++theme++plonetheme.transition/rules.xml</value> </record></registry>
PLONE SYMPOSIUM EAST 2012Blog
# Inside pse12.policy setup.pyinstall_requires=[ ... ‘collective.blog.star’,],
PLONE SYMPOSIUM EAST 2012Blog
<?xml version="1.0"?>
<!-- pse12.policy metadata.xml --><metadata> <version>001</version> <dependencies> ... <dependency>profile-collective.blog.star:default</dependency> </dependencies></metadata>
Content
PLONE SYMPOSIUM EAST 2012Package
$ zopeskel plone pse12.initialcontent
PLONE SYMPOSIUM EAST 2012Package
# Inside pse12.initialcontent setup.pyinstall_requires=[ ‘quintagroup.transmogrifier’,],
PLONE SYMPOSIUM EAST 2012Package
<!-- pse12.initialcontent configure.zcml --><genericsetup:registerProfile name="default" title="pse12.initialcontent (default)" directory="profiles/default" description="Content generation package" provides="Products.GenericSetup.interfaces.EXTENSION" />
PLONE SYMPOSIUM EAST 2012Package
<?xml version="1.0"?>
<!-- pse12.initialcontent metadata.xml --><metadata> <version>001</version> <dependencies> <dependency>profile-pse12.policy:default</dependency> </dependencies></metadata>
PLONE SYMPOSIUM EAST 2012!"" __init__.py!"" configure.zcml!"" profiles# %"" default# !"" metadata.xml# !"" pse12_initialcontent-default.txt# !"" quintagroup.transmogrifier-import.txt# %"" structure# !"" .objects.xml# !"" .portlets.xml# !"" .properties.xml# !"" about# # !"" .marshall.xml# # !"" .objects.xml# # !"" .portlets.xml# # !"" .properties.xml# # !"" about-us# # # !"" .marshall.xml# # # %"" .portlets.xml# # %"" meet-the-team# # !"" .marshall.xml# # %"" .portlets.xml# !"" files# # !"" .marshall.xml# # %"" .portlets.xml# !"" front-page# # !"" .marshall.xml# # %"" .portlets.xml# %"" images# !"" .marshall.xml# !"" .objects.xml# %"" .portlets.xml!"" setuphandlers.py!"" upgrades.py%"" upgrades.zcml
Upgrades and Setuphandlers
PLONE SYMPOSIUM EAST 2012Setuphandlersfrom sixfeetup.utils import helpers as sfutils
def importVariousInitial(context): """Run the setup handlers for the initial profile""" if context.readDataFile('pse12_policy-initial.txt') is None: return members = [ {'id': 'staff', 'password': 'staff', 'roles': ['Manager', 'Member'], 'properties': { 'email': '[email protected]', 'fullname': 'Site Staff', 'username': 'staff' } } ] sfutils.addUserAccounts(members)
PLONE SYMPOSIUM EAST 2012Setuphandlers
<genericsetup:importStep name="pse12.policy: initial" title="pse12.policy: Various Initial steps" description="Initial Setup handlers for pse12.policy" handler="pse12.policy.setuphandlers.importVariousInitial"> <depends name="content"/> </genericsetup:importStep>
PLONE SYMPOSIUM EAST 2012Setuphandlers
from sixfeetup.utils import helpers as sfutils
def importVarious(context): """Run the setup handlers for the default profile""" if context.readDataFile('pse12_policy-default.txt') is None: return # automagically run a plone migration if needed sfutils.runPortalMigration() # automagically run the upgrade steps for this package sfutils.runUpgradeSteps(u'pse12.policy:default')
PLONE SYMPOSIUM EAST 2012Setuphandlers
from sixfeetup.utils import helpers as sfutils
def importVarious(context): """Run the setup handlers for the default profile""" if context.readDataFile('pse12_initialcontent-default.txt') is None: return # automagically run the upgrade steps for this package sfutils.runUpgradeSteps(u'pse12.initialcontent:default')
PLONE SYMPOSIUM EAST 2012Upgrades <!-- pse12.initialcontent upgrades.zcml --> <genericsetup:upgradeStep title="Set up intranet section" description="" source="001" destination="002" handler="pse12.initialcontent.upgrades.intranet_setup" sortkey="10" profile="pse12.initialcontent:default" />
<genericsetup:upgradeStep title="Set up the default pages" description="" source="001" destination="002" handler="pse12.initialcontent.upgrades.default_pages" sortkey="20" profile="pse12.initialcontent:default" />
PLONE SYMPOSIUM EAST 2012from zope.app.component.hooks import getSitefrom Products.CMFCore.utils import getToolByNamefrom sixfeetup.utils import helpers as sfutils
def intranet_setup(context): """Set up the placeful workflow for the intranet """ portal = getSite() # If the intranet doesn't exist, bail out if 'intranet' not in portal.objectIds(): return intranet = portal['intranet'] # If the placeful workflow is already in place, bail out if '.wf_policy_config' in intranet.objectIds(): return placeful_workflow = getToolByName(portal, 'portal_placeful_workflow') product = 'CMFPlacefulWorkflow' intranet.manage_addProduct[product].manage_addWorkflowPolicyConfig() config = placeful_workflow.getWorkflowPolicyConfig(intranet) policy = 'intranet' config.setPolicyBelow(policy=policy) config.setPolicyIn(policy=policy) # Make everything in the intranet `private` path = '/'.join(intranet.getPhysicalPath()) sfutils.publishEverything(context, path, 'hide')
PLONE SYMPOSIUM EAST 2012from zope.app.component.hooks import getSite
def default_pages(context): """There is a bug in quintagroup.transmogrifier that prevents the default page from being set. We will handle it here instead. """ portal = getSite() items = { 'about': dict( id='default_page', type='string', value='about-us'), 'blog': dict( id='layout', type='string', value='blog_view'), } for path, prop in items.items(): obj = portal.unrestrictedTraverse(path, None) # If the object doesn't exist, bail out if obj is None: continue target_obj = None if prop['id'] == 'default_page': target_obj = obj.unrestrictedTraverse(prop['value'], None) # Bail out if the default page target does not exist if target_obj is None: continue obj._setProperty(prop['id'], prop['value'], prop['value']) if target_obj is not None: # ensure that it doesn't show in the navigation target_obj.reindexObject()
Plone Site Recipe
PLONE SYMPOSIUM EAST 2012What is it?
• Create a Plone site
• Run profiles
• Re-create a site
PLONE SYMPOSIUM EAST 2012Add it to buildout
[buildout]parts = plonesite
[plonesite]recipe = collective.recipe.plonesiteinstance = instancezeoserver = zeoserversite-id = Ploneadmin-user = admin
PLONE SYMPOSIUM EAST 2012Add profiles
[plonesite]...profiles-initial = pse12.policy:initialprofiles = pse12.policy:default
PLONE SYMPOSIUM EAST 2012Buildout run
$ bin/buildout install plonesiteInstalling plonesite.Retrieved the admin userAdded Plone SiteQuick installing: []Running profiles: ['pse12.policy:initial']FinishedRunning profiles: ['pse12.policy:default', 'sixfeetup.customfolderalert:default', 'plone.app.debugtoolbar:default']
PLONE SYMPOSIUM EAST 2012Dynamic options
$ bin/buildout plonesite:enabled=false
$ bin/buildout plonesite:site-replace=true
Upgrade Demo
PLONE SYMPOSIUM EAST 2012Links
• sixieskel (http://github.com/sixfeetup/sixieskel)
• pse12-example-buildout (http://github.com/sixfeetup/pse12-example-buildout)
• pse12.policy (http://github.com/sixfeetup/pse12.policy)
• pse12.initialcontent (http://github.com/sixfeetup/pse12.initialcontent)
• quintagroup.transmogrifier (http://pypi.python.org/pypi/quintagroup.transmogrifier)
• collective.blog.star (http://pypi.python.org/pypi/collective.blog.star)
• plonetheme.transition (http://pypi.python.org/pypi/plonetheme.transition/)
PLONE SYMPOSIUM EAST 2012Photo Credits• http://www.flickr.com/photos/naturegeak/5642083189/ (who)
• https://secure.flickr.com/photos/campuspartymexico/5965708420/ (demo)
• https://secure.flickr.com/photos/aon/2171253511/ (realization)
• https://secure.flickr.com/photos/walkingsf/6930636483/ (policy)
• https://secure.flickr.com/photos/myklroventine/3261364899/ (GS)
• https://secure.flickr.com/photos/oskay/2157686638/ (add-ons)
• https://secure.flickr.com/photos/simonpholzman/5132795241/ (plone site)
• https://secure.flickr.com/photos/bitterjug/488731963// (upgrades)
• https://secure.flickr.com/photos/campuspartymexico/5965153009/ (upgrade)
• https://secure.flickr.com/photos/friarsbalsam/4609212148/ (content)
Thanks to
Check out
sixfeetup.com/demos
Questions?