예제 #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 GetItems(directory, ignore_set):
            items = []

            assert os.path.isdir(directory), directory
            is_bin_dir = PythonActivationActivity.BinSubdirs and directory.endswith(os.path.join(*PythonActivationActivity.BinSubdirs))
            
            for item in os.listdir(directory):
                if item in ignore_set:
                    continue

                fullpath = os.path.join(directory, item)
                if not CurrentShell.IsSymLink(fullpath):
                    if ( CurrentShell.CategoryName == "Linux" and 
                         is_bin_dir and 
                         item.startswith("python")
                       ):
                        continue

                    items.append(fullpath)

            return items
예제 #3
0
def Install( lib_name,
             pip_arg=None,
             output_stream=sys.stdout,
           ):
    """
    A replacement for pip install. Will ensure that already installed python libraries are not modified in-place,
    but rather considered as new libraries for the currently activated repository.
    """

    pip_args = pip_arg; del pip_arg

    repo_root = os.getenv(RepositoryBootstrapConstants.DE_REPO_ROOT_NAME)

    scm = GetSCM(repo_root, raise_on_error=False)
    if not scm:
        output_stream.write("ERROR: No SCM is active for '{}'.\n".format(repo_root))
        return -1

    if scm.HasWorkingChanges(repo_root) or scm.HasUntrackedWorkingChanges(repo_root):
        output_stream.write("ERROR: Changes were detected in '{}'; please revert/shelve these changes and run this script again.\n".format(repo_root))
        return -1

    with StreamDecorator(output_stream).DoneManager( line_prefix='',
                                                     prefix="\nResults: ",
                                                     suffix='\n',
                                                   ) as dm:
        pip_command_line = 'pip install "{}"{}'.format( lib_name,
                                                        '' if not pip_args else " {}".format(' '.join(pip_args)),
                                                      )

        dm.stream.write("\nDetecting libraries...")
        with dm.stream.DoneManager( suffix='\n',
                                  ) as this_dm:
            libraries = []

            # ----------------------------------------------------------------------
            def OnOutput(line):
                this_dm.stream.write(line)

                if not line.startswith("Installing collected packages: "):
                    return True

                line = line[len("Installing collected packages: "):]

                for library in line.split(','):
                    library = library.strip()
                    if library:
                        libraries.append(library)

                return False

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

            this_dm.result = Process.Execute( pip_command_line,
                                              OnOutput,
                                              line_delimited_output=True,
                                            )

            if libraries:
                this_dm.result = 0

            if this_dm.result != 0:
                return this_dm.result

        if not libraries:
            return dm.result

        dm.stream.write("Reverting local changes...")
        with dm.stream.DoneManager( suffix='\n',
                                  ) as this_dm:
            this_dm.result = scm.Clean(repo_root, no_prompt=True)[0]

            if this_dm.result != 0:
                return this_dm.result

        dm.stream.write("Reverting existing libraries...")
        with dm.stream.DoneManager( suffix='\n',
                                  ) as this_dm:
            python_lib_dir = os.path.join( os.getenv(RepositoryBootstrapConstants.DE_REPO_GENERATED_NAME), 
                                           PythonActivationActivity.Name, 
                                           _EnvironmentSettings().LibraryDir,
                                         )
            assert os.path.isdir(python_lib_dir), python_lib_dir

            library_items = {}

            for name in os.listdir(python_lib_dir):
                fullpath = os.path.join(python_lib_dir, name)

                if not os.path.isdir(fullpath):
                    continue

                library_items[name.lower()] = CurrentShell.IsSymLink(fullpath)

            # ----------------------------------------------------------------------
            def RemoveItem(name):
                name_lower = name.lower()

                if library_items[name_lower]:
                    this_dm.stream.write("Removing '{}' for upgrade.\n".format(name))
                    os.remove(os.path.join(python_lib_dir, name))
                else:
                    this_dm.stream.write("Removing temporary '{}'.\n".format(name))
                    FileSystem.RemoveTree(os.path.join(python_lib_dir, name))

                del library_items[name_lower]

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

            for library in libraries:
                potential_library_names = [ library, ]

                # Sometimes, a library's name will begin with a 'Py' but be saved in
                # the file system without the 'Py' prefix. Account for that scenario.
                if library.lower().startswith("py"):
                    potential_library_names.append(library[len("py"):])

                for potential_library_name in potential_library_names:
                    potential_library_name_lower = potential_library_name.lower()

                    if potential_library_name_lower not in library_items:
                        continue

                    RemoveItem(potential_library_name)

                    # Is there dist- or egg-info as well?
                    info_items = []

                    for item in six.iterkeys(library_items):
                        if ( item.startswith(potential_library_name_lower) and 
                             (item.endswith(".dist-info") or item.endswith(".egg-info"))
                           ):
                            info_items.append(item)

                    for info_item in info_items:
                        RemoveItem(info_item)

                    break

        dm.stream.write("Installing...")
        with dm.stream.DoneManager() as this_dm:
            this_dm.result = Process.Execute(pip_command_line, this_dm.stream)

        return dm.result
예제 #4
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