예제 #1
0
    def CreatePackageName():
        # Continue traversing parent dirs as long as there is an __init__.py file.
        name_parts = []

        filename = os.path.realpath(mod.__file__)
        if CurrentShell.IsSymLink(filename):
            filename = CurrentShell.ResolveSymLink(filename)

        filename = FileSystem.Normalize(filename)

        directory, name = os.path.split(filename)
        name = os.path.splitext(name)[0]

        while os.path.isfile(os.path.join(directory, "__init__.py")):
            directory, name = os.path.split(directory)
            name_parts.append(name)

        if not name_parts:
            # If we didn't find any __init__ files, it means that this isn't a file
            # that is part of a package. However, we still want to simulate package
            # behavior so that relative imports work as expected.
            if name == "__main__" or getattr(sys, "frozen", False):
                name = "___EntryPoint___"
            else:
                name = "___{}Lib___".format(name)

            assert name not in sys.modules
            sys.modules[name] = None

            return name

        # If here, we are looking at a file in a package. Ensure that the entire
        # package is included with fully qualified names.
        name_parts.reverse()

        for index, name_part in enumerate(name_parts):
            fully_qualified_name = '.'.join(name_parts[:index + 1])

            if fully_qualified_name not in sys.modules:
                # When we load this module, it will be loaded under 'name_part'.
                # Preserve the original module (if it exists).
                temporary_modules[name_part] = sys.modules.pop(name_part, None)

                sys.path.insert(0, directory)
                with CallOnExit(lambda: sys.path.pop(0)):
                    # This will add the module name to sys.modules
                    __import__(name_part)

                sys.modules[fully_qualified_name] = sys.modules[name_part]

            directory = os.path.join(directory, name_part)

        return fully_qualified_name
예제 #2
0
def CodeGeneratorFactory(
    plugin_map,
    name,
    description,
    filename_validation_expression,
    get_optional_metadata_func,  # def Func() -> [ (k, v), ... ]
    create_context_func,  # def Func(metadata, plugin) -> context
    invoke_func,  # def Func(invoke_reason, context, status_stream, verbose_stream, verbose) -> result code
    is_supported_content_func=None,  # def Func(item) -> bool
    postprocess_context_func=None,  # def Func(context, plugin) -> context
    requires_output_name=True,
):
    """Returns a CodeGenerator object"""

    assert get_optional_metadata_func
    assert create_context_func
    assert invoke_func

    calling_frame = inspect.stack()[1]
    calling_mod_filename = os.path.realpath(
        inspect.getmodule(calling_frame[0]).__file__)

    if CurrentShell.IsSymLink(calling_mod_filename):
        calling_mod_filename = CurrentShell.ResolveSymLink(
            calling_mod_filename)

    # ----------------------------------------------------------------------
    @staticderived
    class CodeGenerator(
            AtomicInputProcessingMixin,
            ConditionalInvocationQueryMixin,
            MultipleOutputMixin,
            CodeGeneratorMod.CodeGenerator,
    ):
        # ----------------------------------------------------------------------
        # |
        # |  Public Properties
        # |
        # ----------------------------------------------------------------------
        Name = DerivedProperty(name)
        Description = DerivedProperty(description)
        InputTypeInfo = DerivedProperty(
            FilenameTypeInfo(
                validation_expression=filename_validation_expression))

        OriginalModuleFilename = calling_mod_filename
        RequiresOutputName = requires_output_name

        # ----------------------------------------------------------------------
        # |
        # |  Public Methods
        # |
        # ----------------------------------------------------------------------
        @staticmethod
        @override
        def IsSupportedContent(filename):
            return is_supported_content_func is None or is_supported_content_func(
                filename)

        # ----------------------------------------------------------------------
        # |
        # |  Protected Methods
        # |
        # ----------------------------------------------------------------------
        @classmethod
        @override
        def _GetOptionalMetadata(cls):
            return get_optional_metadata_func() + \
                   [ ( "plugin_settings", {} ),
                   ] + \
                   super(CodeGenerator, cls)._GetOptionalMetadata()

        # ----------------------------------------------------------------------
        @classmethod
        @override
        def _GetRequiredMetadataNames(cls):
            names = [
                "plugin_name",
            ]

            if cls.RequiresOutputName:
                names += [
                    "output_name",
                ]

            names += super(CodeGenerator, cls)._GetRequiredMetadataNames()

            return names

        # ----------------------------------------------------------------------
        @classmethod
        @override
        def _CreateContext(cls, metadata, status_stream):
            if metadata["plugin_name"] not in plugin_map:
                raise CommandLine.UsageException(
                    "'{}' is not a valid plugin".format(
                        metadata["plugin_name"]))

            plugin = plugin_map[metadata["plugin_name"]].Plugin

            # Ensure that all plugin settings are present and that they
            # are the expected type.
            custom_settings = OrderedDict([
                (k, v) for k, v in plugin.GenerateCustomSettingsAndDefaults()
            ])

            plugin_settings = metadata["plugin_settings"]

            for k, v in six.iteritems(plugin_settings):
                if k not in custom_settings:
                    raise CommandLine.UsageException(
                        "'{}' is not a valid plugin setting".format(k))

                desired_type = type(custom_settings[k])

                if type(v) != desired_type:
                    assert isinstance(v,
                                      (str, UnicodeDecodeError)), (v, type(v))
                    plugin_settings[k] = StringSerialization.DeserializeItem(
                        CreateFromPythonType(desired_type), v)

            for k, v in six.iteritems(custom_settings):
                if k not in plugin_settings:
                    plugin_settings[k] = v

            metadata["plugin_settings"] = plugin.PreprocessMetadata(
                plugin_settings)

            # Invoke custom functionality
            context = create_context_func(metadata, plugin)
            context = plugin.PreprocessContext(context)

            context["output_filenames"] = [
                os.path.join(context["output_dir"], filename)
                for filename in plugin.GenerateOutputFilenames(context)
            ]

            context = plugin.PostprocessContext(context)

            if postprocess_context_func:
                context = postprocess_context_func(context, plugin)

            return super(CodeGenerator,
                         cls)._CreateContext(context, status_stream)

        # ----------------------------------------------------------------------
        @classmethod
        @override
        def _InvokeImpl(
            cls,
            invoke_reason,
            context,
            status_stream,
            verbose_stream,
            verbose,
        ):
            return invoke_func(
                cls,
                invoke_reason,
                context,
                status_stream,
                verbose_stream,
                verbose,
                plugin_map[context["plugin_name"]].Plugin,
            )

        # ----------------------------------------------------------------------
        @classmethod
        @override
        def _GetAdditionalGeneratorItems(cls, context):
            # ----------------------------------------------------------------------
            def ProcessorGeneratorItem(item):
                if isinstance(item, six.string_types) and item in plugin_map:
                    return plugin_map[item].Plugin

                return item

            # ----------------------------------------------------------------------

            plugin = plugin_map[context["plugin_name"]].Plugin

            return [ cls,
                     cls.OriginalModuleFilename,
                     plugin,
                   ] + \
                   list(plugin.GetAdditionalGeneratorItems(context)) + \
                   super(CodeGenerator, cls)._GetAdditionalGeneratorItems(context)

    # ----------------------------------------------------------------------

    return CodeGenerator