import re import os import sys print def sanitize_name(name): # get rid of non-alphanumerics name = re.sub('[^A-Za-z0-9]', '', name).lower() # get rid of initial numbers name = re.sub('^[0-9]+', '', name) return name def remove_spaces(name): # get rid of non-alphanumerics name = re.sub('[^A-Za-z0-9]', '', name) return name QUESTION1 = 0 QUESTION2 = 1 QUESTION3 = 2 class Question(object): def __init__(self, phrase): self.phrase = phrase self.takes_params = False class Query(object): def __init__(self): self.queries = [] def append(self, phrase, takes_params=False): q = Question(phrase) q.takes_params = takes_params self.queries.append(q) class QueryName(Query): def __init__(self): super(QueryName, self).__init__() self.name = '' self.sanitize = True def getName(self, default='', q_index=QUESTION1): question = self.queries[q_index] if default: if self.sanitize: default = sanitize_name(default) self.name = default question = self.queries[q_index] if question.takes_params: response = raw_input(question.phrase % self.name) else: response = raw_input(question.phrase) if ((not response or response.upper() == 'Y') and q_index == QUESTION1 and self.name): response = self.name elif response.upper().strip() == 'N': self.getName(self.name, q_index=QUESTION3) elif response.upper().strip() == 'Y': return self.name else: print "Please confirm: " if self.sanitize: response = sanitize_name(response) self.name = response self.getName(q_index=QUESTION2) return self.name # Project Name qn = QueryName() qn.sanitize = False qn.append("What is the name of your project? ") qn.append("Whould you like your project to be named '%s'? [Y/n] ", True) qn.append("Please give a name for your project: ") proj_name = qn.getName() # Package Name qn = QueryName() qn.append("What would you like the top-level package to be named? [%s] ", True) qn.append("Whould you like your package to be named '%s'? [Y/n] ", True) qn.append("Please give a name for your top-level package: ") pkg_name = qn.getName(proj_name) # Skin Name qn = QueryName() qn.sanitize = False qn.append("What would you like to name the project skin? [%s] ", True) qn.append("Whould you like your skin name to be '%s'? [Y/n] ", True) qn.append("Please give a name for project skin: ") skin_name = qn.getName(remove_spaces(proj_name)) # Install dir qn = QueryName() qn.sanitize = False qn.append("Where would you like to install the project (usually Z3_INSTANCE/lib/python)?\n[%s] ", True) qn.append("Whould you like to install your project in '%s'? [Y/n] ", True) qn.append("Please give an install path: ") cwd = os.getcwd() install_dir = qn.getName(cwd) print print "Project name: %s" % proj_name print "Package name: %s" % pkg_name print "Skin name: %s" % skin_name print "Install dir: %s" % install_dir print etc_config = """""" top_config = """ """ vocab_py = """ from zope.app import zapi from zope.app.publisher.interfaces.browser import IBrowserMenu from zope.publisher.browser import TestRequest from zope.schema.vocabulary import SimpleVocabulary def siteSections(context): menu = zapi.getUtility(IBrowserMenu, '%s') menu_items = [ item['title'] for item in menu.getMenuItems(context, TestRequest()) ] return SimpleVocabulary.fromValues(menu_items)""" browser_config = """ """ menu_config = """ """ pageview_py = """from zope.app import zapi from zope.app.publisher.browser import BrowserView class PageView(BrowserView): def renderPage(self): source = zapi.createObject(self.context.type, self.context.text, context=None) view = zapi.getView(source, u'', self.request) return view.render()""" skin_config = """ """ skin_init = '''"""%%SKINNAME%% skin package.""" __docformat__ = "reStructuredText" from zope.interface import Interface from zope.app.rotterdam import Rotterdam class templates(Interface): """Layer to store all templates.""" class images(Interface): """Layer to store all images.""" class css(Interface): """Layer to store all stylesheets.""" class javascript(Interface): """Layer to store all javascript.""" class %%SKINNAME%%(templates, images, css, javascript, Rotterdam): """ This skin consists of its three specific layers plus the rotterdam layer. """ ''' standardmacros_py = """from zope.app.basicskin.standardmacros import StandardMacros as BaseMacros class StandardMacros(BaseMacros): macro_pages = ('main_template', 'view_macros', 'widget_macros', 'dialog_macros', 'navigation_macros') """ onepix_gif = """GIF89a^A^@^A^@~@^@^@???^@^@^@!?^D^A^@^@^@^@,^@^@^@^@^A^@^A^@^@^B^BD^A^@;""" z3_css = """ /* Start CSS for fluid multi-column form layout */ div.row { /*float: left;*/ clear: none; padding: 0.5em; margin-bottom: 1.1em; border: 1px solid #cccccc; } div.separator { clear: both; } div.controls { /*float:left;*/ clear: both; } /* End CSS for fluid multi-column form layout */ div.label { font-weight: bold; } div.field { margin: 4px 0; } div.required:after{ content: " *"; } #drag-feedback-box { border: 1px dotted black; position: absolute; display: none; z-index: 1000; } tr.top, td.top { height: 80; background-color: #000000; } a { text-decoration: none; color: #000066; background-color: transparent; } table { font: 1em Tahoma, Helvetica, Arial, sans-serif; } img { /* turn off image borders. */ border: none; } p { /* Default paragraph style*/ font: 1em Tahoma, Helvetica, Arial, sans-serif; margin: 1em 0em; text-align: left; } p a { text-decoration: underline; } p a:visited { color: Purple; background-color: transparent; } p a:active { color: Red; background-color: transparent; } p img { border: 1px solid Black; margin: 1em; } hr { clear: both; height: 1px; color: #8CACBB; background-color: transparent; } h1, h2, h3, h4, h5, h6 { color: #333333; padding: 0 0; margin: .5em 0; font-family: Tahoma, Helvetica, Arial, sans-serif; } h1 { font-size: 1.8em; } h2 { font-size: 1.2em; } h3 { font-size: 1.0em; } h4 { font-size: 0.9em; } h5 { font-size: 0.8em; color: #666666; } h6 { font-size: 0.7em; } ul { /* list-style-image: url("bullet.gif"); */ margin-top: 1em; margin-bottom: 1em; margin-left: 2em; padding:0; } /* we advise you to use the div.group and span.legend elements instead of these, as the only browser showing legends correctly is IE. They are just included here for completeness */ fieldset { border: 1px solid #8cacbb; margin: 2em 0em 1em 0em; padding: 1em 0em; } legend { background: White; padding: 0.5em; } form { border: none; } textarea { /* Small cosmetic hack which makes textarea gadgets look nicer.*/ font: bold 1em Tahoma, Helvetica, Arial, sans-serif; border: 1px solid #8cacbb; width: 100%; color: Black; background-color: white; } input { /* Small cosmetic fix which makes input gadgets look nicer. */ font: 1em Tahoma, Helvetica, Arial, sans-serif; color: Black; margin: 1px 1px 1px 1px; } select { font: 1em Tahoma, Helvetica, Arial, sans-serif; margin: 1px 1px 1px 1px; } abbr, acronym, .explain { /* Help classes */ border-bottom: 1px dotted Black; background-color: transparent; cursor: help; } code { font-size: 1.2em; color: Black; background-color: #dee7ec; } pre { font-size: 1.2em; padding: 1em; border: 1px solid #8cacbb; color: Black; background-color: #dee7ec; } .netscape4 { /* This hides elements necessary for getting Netscape 4.x to look better. Mostly strategically placed hr tags and ·'s */ display: none; } table.listing { /* The default table for document listings. Contains name, document types, modification times etc in a file-browser-like fashion */ border-collapse: collapse; border-left: 1px solid #FF9900; border-bottom: 1px solid #FF9900; margin: 1em 0em 1em 0em; } table.listing th { background: #333333; border-top: 1px solid #FF9900; border-bottom: 1px solid #FF9900; border-right: 1px solid #FF9900; color: #FFCC00; font-weight: bold; padding: 0em 1em 0em 1em; } table.listing tr.odd { /*every second line should be shaded */ background: #eeeeee; } table.listing tr.even { background: #FFFFFF; } table.listing td { border-right: 1px solid #FF9900; padding: 0.1em 0.4em 0.1em 0.4em; } table.listing a:hover { text-decoration: underline; } table.listing img{ vertical-align: middle; } table.columns { width: 100%; padding: 0; margin: 0; border-collapse: collapse; } table.columns td{ vertical-align: top; } table.columns td.breadcrumbs { } table.columns td.main { background-color: white; padding: 1.0em; border-bottom: 1px solid #092E20; } table.columns td.left { background-color: #cccccc; border-right: 1px solid #000000; border-bottom: 1px solid #000000; padding: 0.5em 0; width: 20%; } table.columns td.right { background-color: #748A49; border-left: 1px solid #092E20; border-bottom: 1px solid #092E20; width: 20%; } #breadcrumbs { background-color: #333333; color: #aaaaaa; margin: 0; padding: 0; margin-top: 2px; padding-top: 7px; padding-left: 5px; border-top: 2px solid #999999; border-bottom: 2px solid #333333; } #breadcrumbs a { color: #ffffff; } span.help img{ vertical-align: middle; padding: 0; margin: 0; } div.box { border: none; margin: 0.5em 0.5em 0em 0.5em; padding: 0; } div.box h4, h5 { font-size: 1em; } div.box h50 { background: #E5E5E5; border: 1px solid #092E20; border-style: solid solid none solid; color: #808080; padding: 0em 1em 0em 1em; text-transform: lowercase; display: inline; font-size: 1em; height: 1em; } div.box h6 { background: #E5E5E5; border: 1px solid #092E20; border-style: solid solid none solid; color: #808080; padding: 0em 1em 0em 1em; text-transform: lowercase; display: block; font-size: 1em; height: 1.2em; } div.box div.body { background-color: #999999; border-collapse: collapse; border: 1px solid #092E20; } div.box .content { padding-left: 0.6em; padding-right: 0.6em; padding-top: 0.1em; padding-bottom: 0.1em; } div.box .even { background-color: #999999; } div.box .odd { background-color: #999999; } .darker { background-color: #7B7AC6; } .hilite { background: #FFFFFF; } .background { border-bottom: 1px solid #7B7AC6; } .description { /* The summary text describing the document */ font: bold 1em Tahoma, Helvetica, Arial, sans-serif; display: block; margin-bottom: 1em; } .footer { background-color: #ffffff; color: #aaaaaa; padding: 0.5em; text-align: right; } .footer_section { padding-left: 1em; } .footer_link { color: #aaaaaa; text-decoration: underline; } div.metadata { font-size: 0.9em; text-align: right; } .context-menu { position: absolute; border: 1px outset; background-color: Menu; color: MenuText; cursor: default; z-index: 1000; visibility: hidden; display: table; } .context-menu-item { padding-left: 10px; padding-right: 10px; padding-top: 2px; padding-bottom: 2px; } .drop-target { border: 2px solid transparent; visibility: hidden; } #navtreecontents a { cursor: pointer; } #navtreecontents loading { display: block; padding-left: 31px; height: 20px; } #navtreecontents expand { background-repeat: no-repeat; padding-left: 14px; display: inline; cursor: pointer; padding-bottom: 0.2em; padding-top: 0.2em; } #navtreecontents icon { background-repeat: no-repeat; padding-left: 20px; display: inline; cursor: auto; padding-bottom: 0.2em; padding-top: 0.2em; } #navtreecontents collection { display: block; margin-left: 10px; /* border: red solid 1pt; */ height: auto; padding-bottom: 0em; padding-top: 0.4em; } .preclass { font-family : monospace; white-space : pre; } th.introspector { vertical-align: top; text-align: right; } .itemViews { border-collapse: collapse; padding-bottom: 2px; padding-top: 6px; margin-top: 0.5em; white-space: nowrap; background: transparent; text-align: right; } .itemViews a { background: transparent; border: 1px solid #ccccff; color: #000066; font-weight: normal; margin-right: 0.3em; padding: 0.1em 0.5em 0.1em 0.5em; } .itemViews a.selected { background-color: #999999; border-bottom: #999999 1px solid; color: #000066; font-weight: normal; } .itemViews a:hover { background-color: #999999; color: #000066; } .actions { background-color: #999999; text-align: right; padding-top: 0.3em; color: Black; border-collapse: collapse; } .actions a{ color: #000066; border-left: 1px dashed #000066; padding: 0 0.5em; } .actions a:hover { background-color: White; } """ pageview_pt = """

""" maintemplate_pt = """
""" macrosnav_pt = """label""" macroscontent_pt = """ %s <metal:title define-slot="title" tal:define=" title view/title|context/title|context/name|context/zope:title|nothing; separator string: :: ; "> <tal:title condition="title" replace="separator" /> <tal:title condition="title" replace="title" /> </metal:title>
123 Main St
Yourtown, US
p: 111.222.3333
f: 111.222.4444
e: us@acme.com
""" macrosstyles_pt = """ body { font: 0.8em Tahoma, Helvetica, Arial, sans-serif; background-color: #ffffff; color: #000000; margin: 5px; padding: 0; } a.navitem_selected, a.navitem_hover, a.navitem, a.navitem:hover { padding-left: 8px; padding-right: 8px; } a.navitem { border-left: 1px solid #ffffff; border-top: 1px solid #ffffff; border-right: 1px solid #aaaaaa; border-bottom: 1px solid #aaaaaa; } a.navitem_selected, a.navitem_hover, a.navitem:hover { background-color: #cccccc; color: #000000; border-left: 1px solid #aaaaaa; border-top: 1px solid #aaaaaa; border-right: 1px solid #ffffff; border-bottom: 1px solid #ffffff; } a.navitem_hover, a.navitem:hover { color: #666666; } span.company_address { padding-right:5px; color: #999999; font: 10px Tahoma, Helvetica, Arial, sans-serif; } a.company_address_link { color: #FFCC00; text-decoration: underline; font: 10px Tahoma, Helvetica, Arial, sans-serif; } a { text-decoration: none; color: #333333; background-color: transparent; } """ types_config = """ """ typesiface_py = '''from zope.i18nmessageid import MessageIDFactory _ = MessageIDFactory('%s') from zope.interface import Interface from zope.schema import TextLine, Text from zope.schema import Field, Bool from zope.schema import List, Choice from zope.schema import Bytes, Date from zope.schema import SourceText from zope.app.folder.interfaces import IFolder from zope.app.container.constraints import ContainerTypesConstraint from zope.app.container.constraints import ItemTypePrecondition class IBasePage(Interface): """A very simple page.""" description = Text( title=u"Description", description=u"A detailed description of the page content.", default=u"", required=False) text = SourceText( title=u"Text", description=u"Text of the page.", default=u"", required=True) type = Choice( title=u"Text type", description=u"Type of the text, e.g. structured text", default=u"zope.source.rest", required = True, vocabulary = "SourceTypes") class IPage(IBasePage): """page content object""" category = Choice( title=_(u"Category"), description=_(u"The category of the page"), required=True, vocabulary="%s", ) ''' page_py = '''from persistent import Persistent from zope.interface import implements from interfaces import IPage class Page(Persistent): implements(IPage)''' print "Creating directories and populating with base files..." pkg_dir = os.path.join(install_dir, pkg_name) browser_dir = os.path.join(pkg_dir, 'browser') skin_dir = os.path.join(browser_dir, 'skin') etc_dir = os.path.join(pkg_dir, 'etc') types_dir = os.path.join(pkg_dir, 'types') pkg_dirs = [pkg_dir, browser_dir, skin_dir, types_dir] images_dir = os.path.join(skin_dir, 'images') js_dir = os.path.join(skin_dir, 'javascript') css_dir = os.path.join(skin_dir, 'styles') templates_dir = os.path.join(skin_dir, 'templates') misc_dirs = [etc_dir, images_dir, js_dir, css_dir, templates_dir] i18ndomain = pkg_name main_nav = pkg_name+'nav' main_nav_name = proj_name+' Site Sections' # Create the dirs for each_dir in pkg_dirs + misc_dirs: try: os.mkdir(each_dir) except: print "\nError!\n" print "Project directory already exists." print "Quitting...\n" sys.exit() # Setup packages for each_dir in pkg_dirs: # touch __init__.py and configure.zcml init = os.path.join(each_dir, '__init__.py') cfg = os.path.join(each_dir, 'configure.zcml') for each_file in [init, cfg]: open(each_file, 'w+').write('') # Add/Customize top-level files instfile = os.path.join(pkg_dir, 'INSTALL') open(instfile, 'w+').write('') chfile = os.path.join(pkg_dir, 'ChangeLog') open(chfile, 'w+').write('') todofile = os.path.join(pkg_dir, 'TODO') open(todofile, 'w+').write('') etcfile = os.path.join(etc_dir, '%s-configure.zcml' % pkg_name) etc = open(etcfile, 'w+') etc.write(etc_config % pkg_name) cfgfile = os.path.join(pkg_dir, 'configure.zcml') cfg = open(cfgfile, 'w+') cfg.write(top_config % (i18ndomain, main_nav_name)) cfg.close() pyfile = os.path.join(pkg_dir, 'vocab.py') py = open(pyfile, 'w+') py.write(vocab_py % main_nav) py.close() # Add/Customize browser-level files browserfile = os.path.join(browser_dir, 'configure.zcml') browser = open(browserfile, 'w+') browser_config = re.sub('%%PKGNAME%%', pkg_name, browser_config) browser_config = browser_config % proj_name browser.write(browser_config) browser.close() menufile = os.path.join(browser_dir, 'menus.zcml') menu = open(menufile, 'w+') menu_config = re.sub('%%MENUNAME%%', main_nav, menu_config) menu.write(menu_config) menu.close() pageviewfile = os.path.join(browser_dir, 'pageview.py') open(pageviewfile, 'w+').write(pageview_py) # Add/Customize skin-level files skinfile = os.path.join(skin_dir, 'configure.zcml') skin = open(skinfile, 'w+') skin_config = re.sub('%%SKINNAME%%', skin_name, skin_config) skin_config = re.sub('%%PKGNAME%%', pkg_name, skin_config) skin.write(skin_config) skin.close() skinfile = os.path.join(skin_dir, '__init__.py') skin = open(skinfile, 'w+') skin_init = re.sub('%%SKINNAME%%', skin_name, skin_init) skin.write(skin_init) skin.close() standardmacrosfile = os.path.join(skin_dir, 'standardmacros.py') open(standardmacrosfile, 'w+').write(standardmacros_py) onepixfile = os.path.join(images_dir, '1px.gif') open(onepixfile, 'w+').write(onepix_gif) z3cssfile = os.path.join(css_dir, 'z3.css') open(z3cssfile, 'w+').write(z3_css) pageviewfile = os.path.join(templates_dir, 'pageview.pt') open(pageviewfile, 'w+').write(pageview_pt) maintemplatefile = os.path.join(templates_dir, 'main_template.pt') open(maintemplatefile, 'w+').write(maintemplate_pt) navfile = os.path.join(templates_dir, 'macros_nav.pt') nav = open(navfile, 'w+') macrosnav_pt = re.sub('%%MAINNAV%%', main_nav, macrosnav_pt) nav.write(macrosnav_pt) contentfile = os.path.join(templates_dir, 'macros_content.pt') content = open(contentfile, 'w+') macroscontent_pt = macroscontent_pt % (proj_name) content.write(macroscontent_pt) stylesfile = os.path.join(templates_dir, 'macros_styles.pt') open(stylesfile, 'w+').write(macrosstyles_pt) # Add/Customize types-level files typesconffile = os.path.join(types_dir, 'configure.zcml') typesconf = open(typesconffile, 'w+') types_config = types_config % (i18ndomain, proj_name) typesconf.write(types_config) typesconf.close() ifacefile = os.path.join(types_dir, 'interfaces.py') iface = open(ifacefile, 'w+') typesiface_py = typesiface_py % (i18ndomain, main_nav_name) iface.write(typesiface_py) iface.close() pagefile = os.path.join(types_dir, 'page.py') open(pagefile, 'w+').write(page_py) print """ Your new z3 project has been created! Don't forget to copy %s/etc/%s-configure.zcml into your z3 instance etc/package-includes directory. You may now create a '%s Page' for your project in the ZMI using the new entry in the "Add" menu. Afterwards, you may view it at the following URL: http://yourhost:8080/++skin++%s/page_name """ % (pkg_name, pkg_name, proj_name, skin_name)