Ejemplo n.º 1
0
def get_interfaces(object, default):
    # we unwind all derived and immediate interfaces using spec.flattened()
    # (providedBy would just give us the immediate interfaces)
    provided_by = list(providedBy(object))
    spec = Declaration(provided_by)
    ifaces = list(spec.flattened())
    return ifaces
Ejemplo n.º 2
0
def get_interfaces(object, default):
    # we unwind all derived and immediate interfaces using spec.flattened()
    # (providedBy would just give us the immediate interfaces)
    provided_by = list(providedBy(object))
    spec = Declaration(provided_by)
    ifaces = list(spec.flattened())
    return ifaces
Ejemplo n.º 3
0
def _get_interfaces(content):
    # we unwind all derived and immediate interfaces using spec.flattened()
    # (providedBy would just give us the immediate interfaces)
    provided_by = list(providedBy(content))
    spec = Declaration(provided_by)
    ifaces = list(spec.flattened()) + [content.__class__]
    return set(ifaces)
Ejemplo n.º 4
0
def _get_interfaces(content):
    # we unwind all derived and immediate interfaces using spec.flattened()
    # (providedBy would just give us the immediate interfaces)
    provided_by = list(providedBy(content))
    spec = Declaration(provided_by)
    ifaces = list(spec.flattened()) + [content.__class__]
    return set(ifaces)
Ejemplo n.º 5
0
def get_interfaces(obj, default):
    """ Useful as KeywordIndex discriminator.  Return a set of all interfaces
    implemented by the object, including inherited interfaces and its class.
    """
    # we unwind all derived and immediate interfaces using spec.flattened()
    # (providedBy would just give us the immediate interfaces)
    provided_by = list(providedBy(obj))
    spec = Declaration(provided_by)
    ifaces = list(spec.flattened()) + [obj.__class__]
    return set(ifaces)
Ejemplo n.º 6
0
def get_interfaces(obj, default):
    """ Useful as KeywordIndex discriminator.  Return a set of all interfaces
    implemented by the object, including inherited interfaces and its class.
    """
    # we unwind all derived and immediate interfaces using spec.flattened()
    # (providedBy would just give us the immediate interfaces)
    provided_by = list(providedBy(obj))
    spec = Declaration(provided_by)
    ifaces = list(spec.flattened()) + [obj.__class__]
    return set(ifaces)
Ejemplo n.º 7
0
def get_interfaces(obj, classes=True):
    """ Return the set of interfaces provided by ``obj``.  Include its
    __class__ if classes is True."""
    # we unwind all derived and immediate interfaces using spec.flattened()
    # (providedBy would just give us the immediate interfaces)
    provided_by = list(providedBy(obj))
    spec = Declaration(provided_by)
    ifaces = list(spec.flattened())
    if classes:
        ifaces = ifaces + [obj.__class__]
    return set(ifaces)
Ejemplo n.º 8
0
def get_interfaces(obj, classes=True):
    """ Return the set of interfaces provided by ``obj``.  Include its
    __class__ if classes is True."""
    # we unwind all derived and immediate interfaces using spec.flattened()
    # (providedBy would just give us the immediate interfaces)
    provided_by = list(providedBy(obj))
    spec = Declaration(provided_by)
    ifaces = list(spec.flattened())
    if classes:
        ifaces = ifaces + [obj.__class__]
    return set(ifaces)
Ejemplo n.º 9
0
    def __provides__(self):
        provided = providedBy(self.field)
        implemented = implementedBy(FieldReadAccessor)

        # Declaration.__add__ is not very smart in zope.interface 5.0.0.
        # It's very easy to produce C3 inconsistent orderings using
        # it, because it uses itself plus any new interfaces from the
        # second argument as the ``__bases__``, ignoring their
        # relative order.
        #
        # Here, we can easily work around that. We know that ``field``
        # will be some sub-class of Attribute, just as we are
        # (FieldReadAccessor <- Method <- Attribute). So there will be
        # overlap, and commonly only IMethod would be added to the end
        # of the list of bases; but since IMethod extends IAttribute,
        # having IAttribute earlier in the bases will be inconsistent.
        # The fix here is to remove those duplicates from the first
        # element so that we don't get into that situation.
        provided_list = list(provided)
        for iface in implemented:
            if iface in provided_list:
                provided_list.remove(iface)
        provided = Declaration(*provided_list)
        # pylint:disable=broad-except
        try:
            return provided + implemented
        except BaseException as e:  # pragma: no cover
            # Sadly, zope.interface catches and silently ignores
            # any exceptions raised in ``__providedBy__``,
            # which is the class descriptor that invokes ``__provides__``.
            # So, for example, if we're in strict C3 mode and fail to produce
            # a resolution order, that gets ignored and we fallback to just
            # what's implemented by the class.
            # That's not good. Do our best to propagate the exception by
            # returning it. There will be downstream errors later.
            return e
Ejemplo n.º 10
0
class SetupTool(UniqueObject, Folder):
    """ Profile-based site configuration manager.
    """
    __implements__ = Declaration(ISetupTool) + Folder.__implements__

    id = 'portal_setup'
    meta_type = 'Portal Setup Tool'

    _product_name = None
    _profile_directory = None
    _root_directory = None

    security = ClassSecurityInfo()

    def __init__(self):

        self._import_registry = ImportStepRegistry()
        self._export_registry = ExportStepRegistry()
        self._export_registry.registerStep('step_registries',
                                           exportStepRegistries,
                                           'Export import / export steps.')
        self._toolset_registry = ToolsetRegistry()

    #
    #   ISetupTool API
    #
    security.declareProtected(ManagePortal, 'getEncoding')

    def getEncoding(self):
        """ See ISetupTool.
        """
        return 'ascii'

    security.declareProtected(ManagePortal, 'getProfileProduct')

    def getProfileProduct(self):
        """ See ISetupTool.
        """
        return self._product_name

    security.declareProtected(ManagePortal, 'getProfileDirectory')

    def getProfileDirectory(self, relative_to_product=False):
        """ See ISetupTool.
        """
        return (relative_to_product and self._profile_directory
                or self._getFullyQualifiedProfileDirectory())

    security.declareProtected(ManagePortal, 'setProfileDirectory')

    def setProfileDirectory(self, path, product_name=None, encoding=None):
        """ See ISetupTool.
        """
        if product_name is not None:

            root = self._root_directory = self._getProductPath(product_name)

            if not os.path.exists(os.path.join(root, path)):
                raise ValueError, 'Invalid path: %s' % path

        else:
            if not os.path.exists(path):
                raise ValueError, 'Invalid path: %s' % path

            self._root_directory = None

        self._profile_directory = path
        self._product_name = product_name

        self._updateImportStepsRegistry(encoding)
        self._updateExportStepsRegistry(encoding)
        self._updateToolsetRegistry(encoding)

    security.declareProtected(ManagePortal, 'getImportStepRegistry')

    def getImportStepRegistry(self):
        """ See ISetupTool.
        """
        return self._import_registry

    security.declareProtected(ManagePortal, 'getImportStepRegistry')

    def getExportStepRegistry(self):
        """ See ISetupTool.
        """
        return self._export_registry

    security.declareProtected(ManagePortal, 'getToolsetRegistry')

    def getToolsetRegistry(self):
        """ See ISetupTool.
        """
        return self._toolset_registry

    security.declareProtected(ManagePortal, 'executeStep')

    def runImportStep(self, step_id, run_dependencies=True, purge_old=True):
        """ See ISetupTool.
        """
        profile_path = self._getFullyQualifiedProfileDirectory()
        encoding = self.getEncoding()
        context = DirectoryImportContext(self, profile_path, purge_old,
                                         encoding)

        info = self._import_registry.getStepMetadata(step_id)

        if info is None:
            raise ValueError, 'No such import step: %s' % step_id

        dependencies = info.get('dependencies', ())

        messages = {}
        steps = []
        if run_dependencies:
            for dependency in dependencies:

                if dependency not in steps:
                    message = self._doRunImportStep(dependency, context)
                    messages[dependency] = message
                    steps.append(dependency)

        message = self._doRunImportStep(step_id, context)
        messages[step_id] = message
        steps.append(step_id)

        return {'steps': steps, 'messages': messages}

    security.declareProtected(ManagePortal, 'runAllSetupSteps')

    def runAllImportSteps(self, purge_old=True):
        """ See ISetupTool.
        """
        profile_path = self._getFullyQualifiedProfileDirectory()
        encoding = self.getEncoding()
        context = DirectoryImportContext(self, profile_path, purge_old,
                                         encoding)

        steps = self._import_registry.sortSteps()
        messages = {}

        for step in steps:
            message = self._doRunImportStep(step, context)
            messages[step] = message

        return {'steps': steps, 'messages': messages}

    security.declareProtected(ManagePortal, 'runExportStep')

    def runExportStep(self, step_id):
        """ See ISetupTool.
        """
        return self._doRunExportSteps([step_id])

    security.declareProtected(ManagePortal, 'runAllExportSteps')

    def runAllExportSteps(self):
        """ See ISetupTool.
        """
        return self._doRunExportSteps(self._export_registry.listSteps())

    security.declareProtected(ManagePortal, 'createSnapshot')

    def createSnapshot(self, snapshot_id):
        """ See ISetupTool.
        """
        context = SnapshotExportContext(self, snapshot_id)
        messages = {}
        steps = self._export_registry.listSteps()

        for step_id in steps:

            handler = self._export_registry.getStep(step_id)

            if handler is None:
                raise ValueError('Invalid export step: %s' % step_id)

            messages[step_id] = handler(context)

        return {
            'steps': steps,
            'messages': messages,
            'url': context.getSnapshotURL(),
            'snapshot': context.getSnapshotFolder()
        }

    security.declareProtected(ManagePortal, 'compareConfigurations')

    def compareConfigurations(self,
                              lhs_context,
                              rhs_context,
                              missing_as_empty=False,
                              ignore_blanks=False,
                              skip=('CVS', '.svn')):
        """ See ISetupTool.
        """
        differ = ConfigDiff(lhs_context, rhs_context, missing_as_empty,
                            ignore_blanks, skip)

        return differ.compare()

    security.declareProtected(ManagePortal, 'markupComparison')

    def markupComparison(self, lines):
        """ See ISetupTool.
        """
        result = []

        for line in lines.splitlines():

            if line.startswith('** '):

                if line.find('File') > -1:
                    if line.find('replaced') > -1:
                        result.append(('file-to-dir', line))
                    elif line.find('added') > -1:
                        result.append(('file-added', line))
                    else:
                        result.append(('file-removed', line))
                else:
                    if line.find('replaced') > -1:
                        result.append(('dir-to-file', line))
                    elif line.find('added') > -1:
                        result.append(('dir-added', line))
                    else:
                        result.append(('dir-removed', line))

            elif line.startswith('@@'):
                result.append(('diff-range', line))

            elif line.startswith(' '):
                result.append(('diff-context', line))

            elif line.startswith('+'):
                result.append(('diff-added', line))

            elif line.startswith('-'):
                result.append(('diff-removed', line))

            elif line == '\ No newline at end of file':
                result.append(('diff-context', line))

            else:
                result.append(('diff-header', line))

        return '<pre>\n%s\n</pre>' % ('\n'.join(
            [('<span class="%s">%s</span>' % (cl, escape(l)))
             for cl, l in result]))

    #
    #   ZMI
    #
    manage_options = (
        Folder.manage_options[:1] + ({
            'label': 'Properties',
            'action': 'manage_tool'
        }, {
            'label': 'Import',
            'action': 'manage_importSteps'
        }, {
            'label': 'Export',
            'action': 'manage_exportSteps'
        }, {
            'label': 'Snapshots',
            'action': 'manage_snapshots'
        }, {
            'label': 'Comparison',
            'action': 'manage_showDiff'
        }) + Folder.manage_options[3:]  # skip "View", "Properties"
    )

    security.declareProtected(ManagePortal, 'manage_tool')
    manage_tool = PageTemplateFile('sutProperties', _wwwdir)

    security.declareProtected(ManagePortal, 'manage_updateToolProperties')

    def manage_updateToolProperties(self, profile_directory, profile_product,
                                    RESPONSE):
        """ Update the tool's settings.
        """
        profile_directory = profile_directory.strip()
        profile_product = profile_product.strip()

        if profile_directory.startswith('.'):
            raise ValueError("Directories begining with '.' are not allowed.")

        if profile_product and profile_directory.startswith('/'):
            raise ValueError(
                "Product may not be specified with absolute directories")

        self.setProfileDirectory(profile_directory, profile_product)

        RESPONSE.redirect('%s/manage_tool?manage_tabs_message=%s' %
                          (self.absolute_url(), 'Properties+updated.'))

    security.declareProtected(ManagePortal, 'manage_importSteps')
    manage_importSteps = PageTemplateFile('sutImportSteps', _wwwdir)

    security.declareProtected(ManagePortal, 'manage_importSelectedSteps')

    def manage_importSelectedSteps(self, ids, run_dependencies, purge_old,
                                   RESPONSE):
        """ Import the steps selected by the user.
        """
        if not ids:
            message = 'No+steps+selected.'

        else:
            steps_run = []
            for step_id in ids:
                result = self.runImportStep(step_id, run_dependencies,
                                            purge_old)
                steps_run.extend(result['steps'])

            message = 'Steps+run:%s' % '+,'.join(steps_run)

        RESPONSE.redirect('%s/manage_importSteps?manage_tabs_message=%s' %
                          (self.absolute_url(), message))

    security.declareProtected(ManagePortal, 'manage_importSelectedSteps')

    def manage_importAllSteps(self, purge_old, RESPONSE):
        """ Import all steps.
        """
        result = self.runAllImportSteps(purge_old)
        message = 'Steps+run:%s' % '+,'.join(result['steps'])

        RESPONSE.redirect('%s/manage_importSteps?manage_tabs_message=%s' %
                          (self.absolute_url(), message))

    security.declareProtected(ManagePortal, 'manage_exportSteps')
    manage_exportSteps = PageTemplateFile('sutExportSteps', _wwwdir)

    security.declareProtected(ManagePortal, 'manage_exportSelectedSteps')

    def manage_exportSelectedSteps(self, ids, RESPONSE):
        """ Export the steps selected by the user.
        """
        if not ids:
            RESPONSE.redirect('%s/manage_exportSteps?manage_tabs_message=%s' %
                              (self.absolute_url(), 'No+steps+selected.'))

        result = self._doRunExportSteps(ids)
        RESPONSE.setHeader('Content-type', 'application/x-gzip')
        RESPONSE.setHeader('Content-disposition',
                           'attachment; filename=%s' % result['filename'])
        return result['tarball']

    security.declareProtected(ManagePortal, 'manage_exportAllSteps')

    def manage_exportAllSteps(self, RESPONSE):
        """ Export all steps.
        """
        result = self.runAllExportSteps()
        RESPONSE.setHeader('Content-type', 'application/x-gzip')
        RESPONSE.setHeader('Content-disposition',
                           'attachment; filename=%s' % result['filename'])
        return result['tarball']

    security.declareProtected(ManagePortal, 'manage_snapshots')
    manage_snapshots = PageTemplateFile('sutSnapshots', _wwwdir)

    security.declareProtected(ManagePortal, 'listSnapshotInfo')

    def listSnapshotInfo(self):
        """ Return a list of mappings describing available snapshots.

        o Keys include:

          'id' -- snapshot ID

          'title' -- snapshot title or ID

          'url' -- URL of the snapshot folder
        """
        result = []
        snapshots = self._getOb('snapshots', None)

        if snapshots:

            for id, folder in snapshots.objectItems('Folder'):

                result.append({
                    'id': id,
                    'title': folder.title_or_id(),
                    'url': folder.absolute_url()
                })
        return result

    security.declareProtected(ManagePortal, 'listProfileInfo')

    def listProfileInfo(self):
        """ Return a list of mappings describing registered profiles.

        o Keys include:

          'id' -- profile ID

          'title' -- profile title or ID

          'description' -- description of the profile

          'path' -- path to the profile within its product

          'product' -- name of the registering product
        """
        return _profile_registry.listProfileInfo()

    security.declareProtected(ManagePortal, 'manage_createSnapshot')

    def manage_createSnapshot(self, RESPONSE, snapshot_id=None):
        """ Create a snapshot with the given ID.

        o If no ID is passed, generate one.
        """
        if snapshot_id is None:
            timestamp = time.gmtime()
            snapshot_id = 'snapshot-%4d%02d%02d%02d%02d%02d' % timestamp[:6]

        self.createSnapshot(snapshot_id)

        RESPONSE.redirect('%s/manage_snapshots?manage_tabs_message=%s' %
                          (self.absolute_url(), 'Snapshot+created.'))

    security.declareProtected(ManagePortal, 'manage_showDiff')
    manage_showDiff = PageTemplateFile('sutCompare', _wwwdir)

    def manage_downloadDiff(self, lhs, rhs, missing_as_empty, ignore_blanks,
                            RESPONSE):
        """ Crack request vars and call compareConfigurations.

        o Return the result as a 'text/plain' stream, suitable for framing.
        """
        comparison = self.manage_compareConfigurations(lhs, rhs,
                                                       missing_as_empty,
                                                       ignore_blanks)
        RESPONSE.setHeader('Content-Type', 'text/plain')
        return _PLAINTEXT_DIFF_HEADER % (lhs, rhs, comparison)

    security.declareProtected(ManagePortal, 'manage_compareConfigurations')

    def manage_compareConfigurations(self, lhs, rhs, missing_as_empty,
                                     ignore_blanks):
        """ Crack request vars and call compareConfigurations.
        """
        lhs_context = self._getImportContext(lhs)
        rhs_context = self._getImportContext(rhs)

        return self.compareConfigurations(lhs_context, rhs_context,
                                          missing_as_empty, ignore_blanks)

    #
    #   Helper methods
    #
    security.declarePrivate('_getProductPath')

    def _getProductPath(self, product_name):
        """ Return the absolute path of the product's directory.
        """
        try:
            product = __import__('Products.%s' % product_name, globals(), {},
                                 ['initialize'])
        except ImportError:
            raise ValueError, 'Not a valid product name: %s' % product_name

        return product.__path__[0]

    security.declarePrivate('_getImportContext')

    def _getImportContext(self, context_id):
        """ Crack ID and generate appropriate import context.
        """
        if context_id.startswith('profile-'):

            context_id = context_id[len('profile-'):]
            info = _profile_registry.getProfileInfo(context_id)

            if info.get('product'):
                path = os.path.join(self._getProductPath(info['product']),
                                    info['path'])
            else:
                path = info['path']

            return DirectoryImportContext(self, path)

        # else snapshot
        context_id = context_id[len('snapshot-'):]
        return SnapshotImportContext(self, context_id)

    security.declarePrivate('_getFullyQualifiedProfileDirectory')

    def _getFullyQualifiedProfileDirectory(self):
        """ Return the fully-qualified directory path of our profile.
        """
        if self._root_directory is not None:
            return os.path.join(self._root_directory, self._profile_directory)

        return self._profile_directory

    security.declarePrivate('_updateImportStepsRegistry')

    def _updateImportStepsRegistry(self, encoding):
        """ Update our import steps registry from our profile.
        """
        fq = self._getFullyQualifiedProfileDirectory()

        f = open(os.path.join(fq, IMPORT_STEPS_XML), 'r')
        xml = f.read()
        f.close()

        info_list = self._import_registry.parseXML(xml, encoding)

        for step_info in info_list:

            id = step_info['id']
            version = step_info['version']
            handler = _resolveDottedName(step_info['handler'])

            dependencies = tuple(step_info.get('dependencies', ()))
            title = step_info.get('title', id)
            description = ''.join(step_info.get('description', []))

            self._import_registry.registerStep(id=id,
                                               version=version,
                                               handler=handler,
                                               dependencies=dependencies,
                                               title=title,
                                               description=description)

    security.declarePrivate('_updateExportStepsRegistry')

    def _updateExportStepsRegistry(self, encoding):
        """ Update our export steps registry from our profile.
        """
        fq = self._getFullyQualifiedProfileDirectory()

        f = open(os.path.join(fq, EXPORT_STEPS_XML), 'r')
        xml = f.read()
        f.close()

        info_list = self._export_registry.parseXML(xml, encoding)

        for step_info in info_list:

            id = step_info['id']
            handler = _resolveDottedName(step_info['handler'])

            title = step_info.get('title', id)
            description = ''.join(step_info.get('description', []))

            self._export_registry.registerStep(id=id,
                                               handler=handler,
                                               title=title,
                                               description=description)

    security.declarePrivate('_updateToolsetRegistry')

    def _updateToolsetRegistry(self, encoding):
        """ Update our toolset registry from our profile.
        """
        fq = self._getFullyQualifiedProfileDirectory()

        f = open(os.path.join(fq, TOOLSET_XML), 'r')
        xml = f.read()
        f.close()

        self._toolset_registry.parseXML(xml, encoding)

    security.declarePrivate('_doRunImportStep')

    def _doRunImportStep(self, step_id, context):
        """ Run a single import step, using a pre-built context.
        """
        handler = self._import_registry.getStep(step_id)

        if handler is None:
            raise ValueError('Invalid import step: %s' % step_id)

        return handler(context)

    security.declarePrivate('_doRunExportSteps')

    def _doRunExportSteps(self, steps):
        """ See ISetupTool.
        """
        context = TarballExportContext(self)
        messages = {}

        for step_id in steps:

            handler = self._export_registry.getStep(step_id)

            if handler is None:
                raise ValueError('Invalid export step: %s' % step_id)

            messages[step_id] = handler(context)

        return {
            'steps': steps,
            'messages': messages,
            'tarball': context.getArchive(),
            'filename': context.getArchiveFilename()
        }