diff --git a/docs/examples.rst b/docs/examples.rst
index c5977bd..faaca4c 100644
--- a/docs/examples.rst
+++ b/docs/examples.rst
@@ -2,6 +2,9 @@
Examples of JSON input files
==============================================================================
+Netbotz
+--------------------
+
NetBotz II Example::
{
@@ -42,6 +45,10 @@ NetBotz II Example::
}]
}
+
+Genbotz Generalization of Netbotz
+----------------------------------
+
GenBotz Example with Organizers (DeviceClasses)::
@@ -101,6 +108,9 @@ GenBotz Example with Organizers (DeviceClasses)::
}]
}
+NetScalar
+--------------------
+
NetScaler Example::
{
diff --git a/docs/index.rst b/docs/index.rst
index 7ae0156..38032c1 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -15,6 +15,7 @@ This is the documentation for the ZenPack Generator tool.
usage
jsonformat
examples
+ use_cases
Indices and tables
diff --git a/docs/jsonformat.rst b/docs/jsonformat.rst
index 9f27133..5541535 100644
--- a/docs/jsonformat.rst
+++ b/docs/jsonformat.rst
@@ -210,12 +210,12 @@ Json Options for a ComponentType::
.. _deviceType:
-deviceType []
+deviceType {}
-------------
Json Options for a DeviceType::
- "deviceType": [{
+ "deviceType": {
"name": "DeviceName",
"names": "DeviceNames",
"klasses": ['DeviceComponent'],
@@ -228,7 +228,7 @@ Json Options for a DeviceType::
"componentTypes": [],
"impacts": [],
"impactedBy": []
- }]
+ }
* name: The Name of the Device Component, Used to define the Module and Class of a Component. [required]
* names: The Plural Form of the Device Component Name. [optional]
@@ -271,6 +271,10 @@ Json Options for a Property::
"mode": 'w',
"value": 10,
"detailDisplay": True,
+ readonly=True,
+ detail_group=None,
+ detail_order=None,
+ addl_detail_args=None,
"gridDisplay": True,
"sortable": True,
"width": 10,
@@ -291,6 +295,19 @@ Json Options for a Property::
* True
* False
* Defaults to True
+* readonly: Allow the property to be modified from the detail pane.
+ * Valid Inputs:
+ * True
+ * False
+ * Defaults to True
+* detail_group: Group the property in the details pane. [Currently unsupported in Zenoss]
+ * Valid Inputs:
+ * string
+* detail_order: Order the property in the details pane. [Currently unsupported in Zenoss]
+ * Valid Inputs:
+ * positive or negative integer
+* addl_detail_args: A free form string to pass the details pane.
+ * A string
* gridDisplay: Display the property in the Grid Component Panel section.
* Valid Inputs:
* True
diff --git a/docs/use_cases.rst b/docs/use_cases.rst
new file mode 100644
index 0000000..982255a
--- /dev/null
+++ b/docs/use_cases.rst
@@ -0,0 +1,64 @@
+==============================================================================
+Specific Examples of ZPG Use Cases
+==============================================================================
+ This document will provide specific use cases and fragments that will
+hopefully guide the users onto a higher plane of ZPG conciousness.
+
+Devices without a Root
+==============================================================================
+
+OracleDB::
+
+In this example OracleDB is a device that inherits its /Device base from the
+parent server, be it Linux, AIX, Solaris, or some "other" operating system.
+This means that it needs to be able to patch itself underneath the device tree
+of that server target type and not have a stand-alone device root.
+
+Thus inside of ZenPacks.zenoss.OracleDB/ZenPacks/zenoss/OracleDB/__init__.py
+we should see:
+
+__init__.py::
+
+ # Define new device relations.
+ NEW_DEVICE_RELATIONS = (
+ ('instance', 'OracleInstance'),
+ ('storage', 'OracleStorage'),
+ ('rac', 'OracleRAC'),
+ ('schema', 'OracleSchema'),
+ )
+
+In order to achieve this you must remove the entire "deviceType" structure out of
+the ZPG json file;
+
+OracleDB.json Example::
+
+ {
+ "id": "ZenPacks.zenoss.OracleDB",
+ "author": "Zenoss",
+ "version": "0.0.1",
+ "compat_zenoss_vers": ">=4.2",
+
+ "deviceClasses": [{
+ "path": "",
+
+ "componentTypes": [
+ {
+ "name": "Instance",
+ "meta_type": "OracleInstance",
+ "properties": [
+ {"name": "sid"},
+ {"name": "name_label"},
+ {"name": "connectionString", "Type": "string"},
+ {"name": "hostname"},
+ {"name": "oracleVersion"},
+ {"name": "databaseName"},
+ {"name": "databaseDBID"},
+ {"name": "databasePlatformName"},
+ {"name": "RACnetworkPeers"},
+ {"name": "instanceRole"},
+ {"name": "publicIP"},
+ {"name": "interconnectIP"}
+ ]
+ },...
+ }]....
+ }
diff --git a/docs/zenpackgenerator.rst b/docs/zenpackgenerator.rst
index e2e3b74..f8dac75 100644
--- a/docs/zenpackgenerator.rst
+++ b/docs/zenpackgenerator.rst
@@ -48,6 +48,7 @@ Prerequisites
* Linux or Mac
* Python 2.7
+* Python setuptools
This tool does NOT require a zenoss server.
diff --git a/zpg/Component.py b/zpg/Component.py
index acf499f..ddc9fad 100644
--- a/zpg/Component.py
+++ b/zpg/Component.py
@@ -8,8 +8,11 @@
#
#
+import logging
+
import inflect
+from .colors import error, warn, debug, info, green, red, yellow
from ._defaults import Defaults
from ._zenoss_utils import KlassExpand, zpDir
from .Property import Property
@@ -41,6 +44,8 @@ def __init__(self,
componentTypes=None,
impacts=None,
impactedBy=None,
+ *args,
+ **kwargs
):
"""Args:
name: Component Name
@@ -65,6 +70,15 @@ def __init__(self,
"""
super(Component, self).__init__(zenpack)
+ self.logger = logger = logging.getLogger('ZenPack Generator')
+ for key in kwargs:
+ do_not_warn = False
+ clsname = self.__class__.__name__
+ layer = "%s:%s" % (clsname, name)
+ msg = "WARNING: [%s] unknown keyword ignored in file: '%s'"
+ margs = (layer, key)
+ if not do_not_warn:
+ warn(self.logger, yellow(msg) % margs)
self.source_template = 'component.tmpl'
self.name = name.split('.')[-1]
self.names = names
diff --git a/zpg/DeviceClass.py b/zpg/DeviceClass.py
index dfcd919..7dbccb9 100644
--- a/zpg/DeviceClass.py
+++ b/zpg/DeviceClass.py
@@ -7,7 +7,9 @@
# file at the top-level directory of this package.
#
#
+import logging
+from .colors import error, warn, debug, info, green, red, yellow
from ._zenoss_utils import KlassExpand
from .Relationship import Relationship
find = Relationship.find
@@ -24,14 +26,17 @@ def __init__(self,
prefix='/zport/dmd',
zPythonClass='Products.ZenModel.Device.Device',
componentTypes=None,
- deviceType=None):
+ deviceType=None,
+ *args,
+ **kwargs
+ ):
'''Args:
path: Destination device class path (the prefix is
automatically prepended)
ZenPack: ZenPack Class Instance
prefix: Destination device class prefix [/zport/dmd]
zPythonClass: The zPythonClass this Device Class references.
- [Products.ZenModel.Device.Device]
+ [Products.ZenModel.Device]
componentTypes: an array of dictionaries used to create
components.
deviceType: a dictionary used to create a device component.
@@ -42,6 +47,14 @@ def __init__(self,
self.id = self.path
self.subClasses = {}
self.zPythonClass = KlassExpand(self.zenpack, zPythonClass)
+ self.logger = logger = logging.getLogger('ZenPack Generator')
+ for key in kwargs:
+ do_not_warn = False
+ layer = self.__class__.__name__
+ msg = "WARNING: JSON keyword ignored in layer '%s': '%s'"
+ margs = (layer, key)
+ if not do_not_warn:
+ warn(self.logger, yellow(msg) % margs)
if deviceType:
self.DeviceType(**deviceType)
else:
diff --git a/zpg/License.py b/zpg/License.py
index eb9d5d0..1e550cc 100644
--- a/zpg/License.py
+++ b/zpg/License.py
@@ -88,16 +88,16 @@ def __init__(self, zenpack, id_):
elif id_ in dflt_licenses:
self.id = id_
- self.header = load_header('Licenses', self.id)
- self.license = load_license('Licenses', self.id)
+ self.header = load_header(tpath, self.id)
+ self.license = load_license(tpath, self.id)
else:
# Default GPlv2
info(log,
red('Specified License [%s] not known. Defaulting to GPLv2.'
% id_))
self.id = 'GPLv2'
- self.header = load_header('Licenses', self.id)
- self.license = load_license('Licenses', self.id)
+ self.header = load_header(tpath, self.id)
+ self.license = load_license(tpath, self.id)
def header(self):
return self.header
diff --git a/zpg/Organizer.py b/zpg/Organizer.py
index 4fd59c1..035aeb0 100644
--- a/zpg/Organizer.py
+++ b/zpg/Organizer.py
@@ -8,10 +8,12 @@
#
#
+import logging
import sys
from lxml import etree
+from .colors import error, warn, debug, info, green, red, yellow
from .Property import Property
from ._zenoss_utils import KlassExpand
@@ -23,8 +25,10 @@ class Organizer(object):
def __init__(self,
zenpack,
name,
- type_,
- properties=None
+ type_=None,
+ properties=None,
+ *args,
+ **kwargs
):
"""Args:
name: Organizer Name in the form of a Slash separated path.
@@ -36,6 +40,27 @@ def __init__(self,
self.id = name
self.type_ = type_
self.properties = {}
+ self.logger = logger = logging.getLogger('ZenPack Generator')
+ for key in kwargs:
+ do_not_warn = False
+ layer = self.__class__.__name__
+ msg = "WARNING: JSON keyword ignored in layer '%s': '%s'"
+ margs = (layer, key)
+ if key == "Type":
+ msg = "WARNING: JSON keyword deprecated in '%s' layer. "\
+ "'%s' is now '%s'."
+ margs = (layer, key, key.lower())
+ self.type_ = kwargs[key]
+ elif key == "type":
+ self.type_ = type_ = kwargs[key]
+ do_not_warn = True
+ elif key == "Contained":
+ msg = "WARNING: JSON keyword deprecated in '%s' layer. "\
+ "'%s' is now '%s'."
+ margs = (layer, key, key.lower())
+ self.contained = kwargs[key]
+ if not do_not_warn:
+ warn(self.logger, yellow(msg) % margs)
# Dict loading
if properties:
for p in properties:
diff --git a/zpg/Property.py b/zpg/Property.py
index 58b2699..5245f38 100644
--- a/zpg/Property.py
+++ b/zpg/Property.py
@@ -8,9 +8,13 @@
#
#
+import logging
+import re
+
import inflect
from lxml import etree
-import re
+
+from .colors import error, warn, debug, info, green, red, yellow
plural = inflect.engine().plural
@@ -27,7 +31,14 @@ def __init__(self,
detailDisplay=True,
gridDisplay=True,
sortable=True,
- panelRenderer=None):
+ panelRenderer=None,
+ readonly=True,
+ detail_group=None,
+ detail_order=None,
+ addl_detail_args=None,
+ *args,
+ **kwargs
+ ):
"""Args:
name: Property name
value: default value [None]
@@ -56,6 +67,27 @@ def __init__(self,
self.panelRenderer = panelRenderer
self.type_ = type_ if type_ else value
self.value = value
+ self.readonly = readonly
+ self.detail_group = detail_group
+ self.detail_order = detail_order
+ self.addl_detail_args = addl_detail_args
+ self.logger = logger = logging.getLogger('ZenPack Generator')
+ for key in kwargs:
+ do_not_warn = False
+ clsname = self.__class__.__name__
+ layer = "%s:%s" % (clsname, self.name)
+ msg = "WARNING: [%s] unknown keyword ignored in file: '%s'"
+ margs = (layer, key)
+ if key == "Type":
+ msg = "WARNING: [%s] keyword deprecated: "\
+ "'%s' is now '%s'."
+ margs = (layer, key, key.lower())
+ self.type_ = type_ = kwargs[key]
+ elif key == "type":
+ self.type_ = type_ = kwargs[key]
+ do_not_warn = True
+ if not do_not_warn:
+ warn(self.logger, yellow(msg) % margs)
def Schema(self):
"""Given the type return the correct Schema."""
@@ -68,6 +100,23 @@ def Schema(self):
else:
return 'TextLine'
+ @property
+ def detail_args(self):
+ """Return additional detail arguements"""
+
+ detail_args = ", readonly=%s" % self.readonly
+
+ if self.detail_group:
+ detail_args = ", group=u'%s'" % self.detail_group
+
+ if self.detail_order:
+ detail_args = ", order=%s" % self.detail_order
+
+ if self.addl_detail_args:
+ detail_args = ", %s" % self.addl_detail_args
+
+ return detail_args
+
@property
def type_(self):
"""Return the type"""
diff --git a/zpg/Relationship.py b/zpg/Relationship.py
index d4ee911..0695fac 100644
--- a/zpg/Relationship.py
+++ b/zpg/Relationship.py
@@ -8,28 +8,72 @@
#
#
+import logging
+
+from .colors import error, warn, debug, info, green, red, yellow
-class Relationship(object):
+class Relationship(object):
'''ZenPack Relationship Management'''
+ valid_relationship_types = ['1-M', 'M-M', '1-1']
relationships = {}
def __init__(self,
ZenPack,
componentA,
componentB,
- type_='1-M',
- contained=True):
+ type_=None,
+ contained=True,
+ *args,
+ **kwargs
+ ):
"""Args:
ZenPack: A ZenPack Class instance
componentA: Parent component string id
componentB: Child component string id
- type_: Relationship type_. Valid inputs [1-1,1-M,M-M]
+ type_: Relationship type_. Valid inputs [1-1, 1-M, M-M]
contained: ComponentA contains ComponentB True or False
"""
self.ZenPack = ZenPack
- from Component import Component
+ from .Component import Component
+
+ self.logger = logger = logging.getLogger('ZenPack Generator')
+ name = "-".join([componentA, componentB])
+ layer = "%s:%s" % (self.__class__.__name__, name)
+ if type_ not in self.valid_relationship_types:
+ msg = "WARNING: [%s] unknown type: '%s'. Defaulted to '%s'. "
+ layer = "%s:%s" % (self.__class__.__name__, name)
+ margs = (layer, type, '1-M')
+ if type_ == 'M-1':
+ a_b = (componentA, componentB)
+ msg += "Reversed '%s' and '%s'." % a_b
+ swap = componentB
+ componentB = componentA
+ componentA = swap
+ if type_ is not None:
+ warn(self.logger, yellow(msg) % margs)
+ type_ = '1-M'
+ for key in kwargs:
+ do_not_warn = False
+ msg = "WARNING: [%s] unknown keyword ignored in file: '%s'"
+ margs = (layer, key)
+ if key == "Type":
+ msg = "WARNING: [%s] keyword deprecated: "\
+ "'%s' is now '%s'."
+ margs = (layer, key, key.lower())
+ self.type_ = kwargs[key]
+ elif key == "type":
+ self.type_ = type_ = kwargs[key]
+ do_not_warn = True
+ elif key == "Contained":
+ msg = "WARNING: [%s] keyword deprecated: "\
+ "'%s' is now '%s'."
+ margs = (layer, key, key.lower())
+ self.contained = kwargs[key]
+ if not do_not_warn:
+ warn(self.logger, yellow(msg) % margs)
+
lookup = Component.lookup
self.components = lookup(
ZenPack, componentA), lookup(ZenPack, componentB)
diff --git a/zpg/Templates/component.tmpl b/zpg/Templates/component.tmpl
index 7328f73..f549d47 100644
--- a/zpg/Templates/component.tmpl
+++ b/zpg/Templates/component.tmpl
@@ -53,12 +53,6 @@ class ${shortklass}(#echo ', '.join($klassNames)#):
},),
},)
-## # Query for events by id instead of name.
-## event_key = "ComponentId"
-##
-## def getIconPath(self):
-## return '/++resource++cloudstack/img/cloudstack.png'
-##
def device(self):
'''
Return device under which this component/device is contained.
@@ -76,6 +70,24 @@ class ${shortklass}(#echo ', '.join($klassNames)#):
'Unable to determine parent at %s (%s) '
'while getting device for %s' % (
obj, exc, self))
+
+#if not $device
+ def manage_deleteComponent(self, REQUEST=None):
+ """
+ Delete Component
+ """
+ try:
+ # Default to using built-in method in Zenoss >= 4.2.4.
+ return super(${shortklass}, self).manage_deleteComponent(REQUEST)
+ except AttributeError:
+ # Fall back to copying the Zenoss 4.2.4 implementation.
+ url = None
+ if REQUEST is not None:
+ url = self.device().absolute_url()
+ self.getPrimaryParent()._delObject(self.id)
+ if REQUEST is not None:
+ REQUEST['RESPONSE'].redirect(url)
+#end if
#for $key in $updateComponents
#if $key == '1'
#for $c in $updateComponents['1']
@@ -142,7 +154,7 @@ class I${shortklass}Info(I${type_}Info):
#if $properties.values()
#for $prop in $properties.values()
- $prop.id = schema.${prop.Schema}(title=_t(u'$prop.names'))
+ $prop.id = schema.${prop.Schema}(title=_t(u'$prop.names')$prop.detail_args)
#end for
#end if
#end if
diff --git a/zpg/Templates/configure.zcml.tmpl b/zpg/Templates/configure.zcml.tmpl
index 816a2c5..6954e59 100644
--- a/zpg/Templates/configure.zcml.tmpl
+++ b/zpg/Templates/configure.zcml.tmpl
@@ -8,12 +8,14 @@
#for $c in sorted($components.values())
+#if $c.displayInfo
+#end if
#end for
#end if
diff --git a/zpg/Templates/utils.tmpl b/zpg/Templates/utils.tmpl
index 251c645..df931dd 100644
--- a/zpg/Templates/utils.tmpl
+++ b/zpg/Templates/utils.tmpl
@@ -10,6 +10,9 @@ from Products.Zuul.interfaces import ICatalogTool
from zope.event import notify
from Products.Zuul.catalog.events import IndexingEvent
+from Products.ZenUtils.guid.interfaces import IGlobalIdentifier
+import functools
+import importlib
import logging
LOG = logging.getLogger('${zenpack.id}.utils')
@@ -157,3 +160,43 @@ def string_to_int(value):
i = value
return i
+
+def guid(obj):
+ '''
+ Return GUID for obj.
+ '''
+
+ return IGlobalIdentifier(obj).getGUID()
+
+def require_zenpack(zenpack_name, default=None):
+ '''
+ Decorator with mandatory zenpack_name argument.
+
+ If zenpack_name can't be imported, the decorated function or method
+ will return default. Otherwise it will execute and return as
+ written.
+
+ Usage looks like the following:
+
+ @require_zenpack('ZenPacks.zenoss.Impact')
+ @require_zenpack('ZenPacks.zenoss.vCloud')
+ def dothatthingyoudo(args):
+ return "OK"
+
+ @require_zenpack('ZenPacks.zenoss.Impact', [])
+ def returnalistofthings(args):
+ return [1, 2, 3]
+ '''
+ def wrap(f):
+ @functools.wraps(f)
+ def wrapper(*args, **kwargs):
+ try:
+ importlib.import_module(zenpack_name)
+ except ImportError:
+ return
+
+ return f(*args, **kwargs)
+
+ return wrapper
+
+ return wrap
diff --git a/zpg/ZenPack.py b/zpg/ZenPack.py
index f910b43..fe16c79 100644
--- a/zpg/ZenPack.py
+++ b/zpg/ZenPack.py
@@ -8,12 +8,15 @@
#
##############################################################################
+import logging
import os
from git import Repo
from .memoize import memoize
+from .colors import error, warn, debug, info, green, red, yellow
+from ._defaults import Defaults
from ._zenoss_utils import prepId
from .Component import Component
from .ComponentJS import ComponentJS
@@ -31,7 +34,6 @@
from .ImpactPy import ImpactPy
from .ImpactZcml import ImpactZcml
-from ._defaults import Defaults
defaults = Defaults()
@@ -57,6 +59,8 @@ def __init__(self,
deviceClasses=None,
relationships=None,
opts=None,
+ *args,
+ **kwargs
):
self.id = id
@@ -73,6 +77,14 @@ def __init__(self,
self.version = version
self.license = License(self, license)
self.prepname = prepId(id).replace('.', '_')
+ self.logger = logger = logging.getLogger('ZenPack Generator')
+ for key in kwargs:
+ do_not_warn = False
+ layer = self.__class__.__name__
+ msg = "WARNING: JSON keyword ignored in layer '%s': '%s'"
+ margs = (layer, key)
+ if not do_not_warn:
+ warn(self.logger, yellow(msg) % margs)
if install_requires:
if isinstance(install_requires, basestring):
self.install_requires = [install_requires]
diff --git a/zpg/ZenPackUI.py b/zpg/ZenPackUI.py
index 1a546e1..6a176db 100644
--- a/zpg/ZenPackUI.py
+++ b/zpg/ZenPackUI.py
@@ -21,7 +21,7 @@ def __init__(self, ZenPack):
self.zenpack = ZenPack
self.source_template = 'zenpackjs.tmpl'
self.dest_file = "%s/resources/js/%s.js" % (
- zpDir(self.zenpack), self.zenpack.id)
+ zpDir(self.zenpack), self.zenpack.prepname)
def write(self):
# Update the components just before we need them.
diff --git a/zpg/_defaults.py b/zpg/_defaults.py
index fd5bf70..6b48e25 100644
--- a/zpg/_defaults.py
+++ b/zpg/_defaults.py
@@ -26,7 +26,7 @@
'author': 'ZenossLabs ',
'author_email': 'labs@zenoss.com',
'description': 'A tool to assist building zenpacks.',
- 'version': '1.0.11',
+ 'version': '1.0.12',
'license': 'GPLv2',
'component_classes': [
'Products.ZenModel.DeviceComponent.DeviceComponent',
diff --git a/zpg/api.py b/zpg/api.py
index efde59d..96d9dcc 100644
--- a/zpg/api.py
+++ b/zpg/api.py
@@ -45,7 +45,7 @@ def __init__(self):
group1 = self.add_argument_group('standard arguments')
group2 = self.add_argument_group('special arguments')
group1.add_argument("input", type=str, # FileType('rt'),
- default=sys.stdin, nargs="?",
+ default='', nargs="?",
help="input file")
group1.add_argument("dest", type=str, nargs="?",
default=prefix,
@@ -65,19 +65,52 @@ def __init__(self):
group1.add_argument("-v", "--verbose", action="count",
dest="verbose", default=0,
help="Increase output verbosity")
+ group1.add_argument("-c", "--clean", action="store_true",
+ dest="clean", default=False,
+ help="Cleans destination path before generating")
group2.add_argument('-V', "--version", action="store_true",
dest="version", default=False,
help="Display version of %(prog)s")
+def replacer(match):
+ new_string = matched = match.group(0)
+ if matched.startswith('/') or matched.startswith("#"):
+ new_string = ''
+ return new_string
+
+
+def remove_comments(text):
+ """Removes the comments from a JSON, YAML or Python file
+ """
+ pattern = r'#.*?$|//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"'
+ flags = re.DOTALL | re.MULTILINE
+ engine = re.compile(pattern, flags)
+ lines = re.sub(engine, replacer, text).split("\n")
+ return "\n".join(line for line in lines if line.strip())
+
+
+def remove_folder(fpath):
+ removed = []
+ if os.path.exists(fpath):
+ for root, folders, files in os.walk(fpath, topdown=False):
+ for file in files:
+ filepath = os.path.join(root, file)
+ os.remove(filepath)
+ removed.append(filepath)
+ for folder in folders:
+ folderpath = os.path.join(root, folder)
+ if os.path.exists(folderpath):
+ os.removedirs(folderpath)
+ removed.append(folderpath)
+
+
class TemplateJSONDecoder(json.JSONDecoder):
def decode(self, json_string):
"""
json_string is basically string that you give to json.loads method
"""
- json_string = re.sub('"Contained"', '"contained"', json_string)
- json_string = re.sub('"Type"', '"type_"', json_string)
- json_string = re.sub('"type"', '"type_"', json_string)
+ json_string = remove_comments(json_string)
default_obj = super(TemplateJSONDecoder, self).decode(json_string)
return default_obj
@@ -130,11 +163,16 @@ def generate(filename=None):
sys.exit(0)
if not filename or not os.path.exists(filename):
- if not opts.input or not os.path.exists(str(opts.input)):
+ filename = opts.input
+ # Make sure filename is an expanded, absolute path
+ if filename.startswith('~'):
+ filename = os.path.expanduser(filename)
+ elif filename.startswith('.'):
+ filename = os.path.abspath(filename)
+ if not filename or not os.path.exists(filename):
err_msg = "Required input file missing. Exiting...\n"
error(logger, err_msg)
sys.exit(1)
- filename = opts.input
if not os.path.exists(filename):
err_msg = "Input file does not exist! %s" % filename
@@ -160,8 +198,12 @@ def generate(filename=None):
debug(logger, ' Loaded.')
debug(logger, 'Populating ZenPack...')
zp_json = ZenPack(**jsi)
+ fpath = os.path.join(opts.dest, zp_json.id)
debug(logger, 'Done ZenPack populating.')
debug(logger, 'Writing output...')
+ if opts.clean:
+ info(logger, 'Cleaning: %s' % fpath)
+ remove_folder(fpath)
zp_json.write()
debug(logger, 'Done writing.')
diff --git a/zpg/tests/test_Configure.py b/zpg/tests/test_Configure.py
index 6588283..d79a604 100644
--- a/zpg/tests/test_Configure.py
+++ b/zpg/tests/test_Configure.py
@@ -58,7 +58,8 @@ def test_findCustomPathsTrue(self):
dc.addComponentType('Blade')
dc.addComponentType('Fan')
- Relationship(self.zp, 'Enclosure', 'Fan', type_='1-M', contained=False)
+ Relationship(self.zp, 'Enclosure',
+ 'Fan', type_='1-M', contained=False)
Relationship(self.zp, 'Enclosure',
'Blade', type_='1-M', contained=False)
self.assertTrue(self.zp.configure_zcml.customPathReporters())
diff --git a/zpg/tests/test_pep8_conformance.py b/zpg/tests/test_pep8_conformance.py
index 65b5233..83aaa2b 100644
--- a/zpg/tests/test_pep8_conformance.py
+++ b/zpg/tests/test_pep8_conformance.py
@@ -20,7 +20,7 @@ class WriteTemplatesBase(unittest.TestCase):
def test_pep8_conformance(self):
"""Test that we conform to PEP8."""
- pep8style = pep8.StyleGuide(quiet=True)
+ pep8style = pep8.StyleGuide(show_source=True)
# assume this file lives in git_repo/zpg/tests
current_file = os.path.abspath(__file__)
current_folder = os.path.dirname(current_file)
@@ -32,7 +32,7 @@ def test_pep8_conformance(self):
for f in files
if f[-3:] == ".py"
if f[:5] != "test_"))
- results = pep8style.check_files(filepaths)
+ results = pep8style.check_files(sorted(filepaths))
errors = str(results.total_errors)
msgs = [
"Found %s code style errors (and warnings)." % errors,