Ejemplo n.º 1
0
        public UnityReferencesTracker(
            Lifetime lifetime,
            IEnumerable <IUnityReferenceChangeHandler> handlers,
            ISolution solution,
            ISolutionLoadTasksScheduler scheduler,
            ModuleReferenceResolveSync moduleReferenceResolveSync,
            ChangeManager changeManager,
            IViewableProjectsCollection projects,
            ILogger logger)
        {
            myAllProjectLifetimes = new Dictionary <IProject, Lifetime>();
            myUnityProjects       = new HashSet <IProject>();

            myHandlers = handlers.ToList();
            myLifetime = lifetime;
            myLogger   = logger;
            mySolution = solution;
            myModuleReferenceResolveSync = moduleReferenceResolveSync;
            myChangeManager = changeManager;
            myProjects      = projects;

            // At PreparePsiModules, we know what references we have, so we know if we're a Unity project. This is where
            // we'll initialise our custom PSI module. We have to initialise our PSI module before Done, or the
            // PersistentIndexManager will clean out the "orphaned" external (YAML) files and we'll have to reparse all
            // files on every startup
            scheduler.EnqueueTask(new SolutionLoadTask("Preparing Unity project", SolutionLoadTaskKinds.PreparePsiModules,
                                                       OnSolutionPreparePsiModules));
        }
Ejemplo n.º 2
0
            public SolutionStateNotifier([NotNull] Lifetime lifetime,
                                         [NotNull] ISolution solution,
                                         [NotNull] ISolutionLoadTasksScheduler scheduler,
                                         [NotNull] SolutionStateTracker solutionStateTracker)
            {
                if (lifetime == null)
                {
                    throw new ArgumentNullException("lifetime");
                }
                if (solution == null)
                {
                    throw new ArgumentNullException("solution");
                }
                if (scheduler == null)
                {
                    throw new ArgumentNullException("scheduler");
                }
                if (solutionStateTracker == null)
                {
                    throw new ArgumentNullException("solutionStateTracker");
                }

                scheduler.EnqueueTask(new SolutionLoadTask("SolutionStateTracker",
                                                           SolutionLoadTaskKinds.Done, () => solutionStateTracker.HandleSolutionOpened(solution)));

                lifetime.AddAction(solutionStateTracker.HandleSolutionClosed);
            }
        public UnityReferencesTracker(
            Lifetime lifetime,

            IEnumerable <IHandler> handlers,
            ISolution solution,

            ISolutionLoadTasksScheduler scheduler,
            IShellLocks shellLocks,

            ModuleReferenceResolveSync moduleReferenceResolveSync,
            ChangeManager changeManager,
            IViewableProjectsCollection projects,
            ILogger logger
            )
        {
            myProjectLifetimes = new Dictionary <IProject, Lifetime>();

            myHandlers   = handlers.ToList();
            myLifetime   = lifetime;
            myLogger     = logger;
            mySolution   = solution;
            myShellLocks = shellLocks;
            myModuleReferenceResolveSync = moduleReferenceResolveSync;
            myChangeManager = changeManager;
            myProjects      = projects;

            scheduler.EnqueueTask(new SolutionLoadTask("Checking for Unity projects", SolutionLoadTaskKinds.Done, Register));
        }
Ejemplo n.º 4
0
            public SolutionStateNotifier([NotNull] Lifetime lifetime,
                                         [NotNull] ISolution solution,
                                         [NotNull] ISolutionLoadTasksScheduler scheduler,
                                         [NotNull] SolutionStateTracker solutionStateTracker,
                                         [NotNull] IPsiServices psiServices)
            {
                if (lifetime == null)
                {
                    throw new ArgumentNullException("lifetime");
                }
                if (solution == null)
                {
                    throw new ArgumentNullException("solution");
                }
                if (scheduler == null)
                {
                    throw new ArgumentNullException("scheduler");
                }
                if (solutionStateTracker == null)
                {
                    throw new ArgumentNullException("solutionStateTracker");
                }

                scheduler.EnqueueTask(new SolutionLoadTask("SolutionStateTracker",
                                                           SolutionLoadTaskKinds.SolutionContainer, () => solutionStateTracker.HandleSolutionContainerCreated(solution)));
                scheduler.EnqueueTask(new SolutionLoadTask("SolutionStateTracker",
                                                           SolutionLoadTaskKinds.Done, () => solutionStateTracker.HandleSolutionOpened(solution)));
                scheduler.EnqueueTask(new SolutionLoadTask("SolutionStateTracker",
                                                           SolutionLoadTaskKinds.AfterDone, () => psiServices.CachesState.IsIdle.WhenTrueOnce(lifetime, () =>
                                                                                                                                              solutionStateTracker.HandlePsiLoaded(solution))));
                lifetime.AddAction(solutionStateTracker.HandleSolutionClosed);
            }
Ejemplo n.º 5
0
        public MonoInstallTrigger(Lifetime lifetime, ILogger logger, ISolutionLoadTasksScheduler scheduler,
                                  ISolution solution, UnitySolutionTracker unitySolutionTracker, UnityHost host)
        {
            if (PlatformUtil.RuntimePlatform != PlatformUtil.Platform.MacOsX)
            {
                return;
            }

            scheduler.EnqueueTask(new SolutionLoadTask("Check mono runtime", SolutionLoadTaskKinds.AfterDone, () =>
            {
                if (!unitySolutionTracker.IsUnityGeneratedProject.Value)
                {
                    return;
                }

                if (!HasModernUnityProjects(solution))
                {
                    return;
                }

                solution.Locks.Tasks.Queue(lifetime, () =>
                {
                    var wellKnownMonoRuntimes = MonoRuntimeDetector.DetectWellKnownMonoRuntimes();
                    var installedValidMono    = wellKnownMonoRuntimes
                                                .Any(runtime =>
                    {
                        var parsedVersion = string.Empty;
                        try
                        {
                            parsedVersion = ProcessOutputUtil.ExtractMonoVersion(runtime.ExePath);
                        }
                        catch (Exception e)
                        {
                            logger.Warn(e);
                        }

                        // if we fail to parse version - consider it is old
                        if (Version.TryParse(parsedVersion, out var version))
                        {
                            return(version.Major >= 5 && version.Minor >= 16);    // mono 5.16+ supports C# 7.3
                        }
                        logger.Warn("Failed to parse ProcessOutputUtil.ExtractMonoVersion output.");
                        return(false);
                    });

                    if (!installedValidMono)
                    {
                        solution.Locks.ExecuteOrQueue(lifetime, "Show install mono dialog",
                                                      () => { host.PerformModelAction(model => model.ShowInstallMonoDialog()); });
                    }
                });
            }));
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ReferencedAnalyzersCache"/> class.
        /// </summary>
        /// <param name="lifetime">The lifetime of the component</param>
        /// <param name="solution">The current solution</param>
        /// <param name="threading">The threading API</param>
        /// <param name="solutionLoadTasksScheduler">Solution load task scheduler</param>
        /// <param name="projectModelSynchronizer">The project model synchronizer</param>
        /// <param name="packageInstallerServices">NuGet installer services API</param>
        /// <param name="packageInstallerEvents">NuGet installer events API</param>
        public ReferencedAnalyzersCache(
            Lifetime lifetime,
            ISolution solution,
            IThreading threading,
            ISolutionLoadTasksScheduler solutionLoadTasksScheduler,
            ProjectModelSynchronizer projectModelSynchronizer,
            Lazy <Optional <IVsPackageInstallerServices> > packageInstallerServices,
            Lazy <Optional <IVsPackageInstallerEvents> > packageInstallerEvents)
        {
            this.solution  = solution;
            this.threading = threading;
            this.projectModelSynchronizer = projectModelSynchronizer;
            this.packageInstallerEvents   = packageInstallerEvents.Value.CanBeNull;
            this.packageInstallerServices = packageInstallerServices.Value.CanBeNull;

            this.syncObject = new object();

            this.referencedAnalyzers = new OneToSetMap <string, string>();

            this.groupingEvent = threading.GroupingEvents.CreateEvent(
                lifetime,
                "StyleCop::AnalyzersCache",
                TimeSpan.FromSeconds(2),
                Rgc.Guarded,
                this.DoResetAnalyzersCache);

            if (!this.IsNuGetAvailable)
            {
                Logger.LogMessage(
                    LoggingLevel.VERBOSE,
                    "[StyleCop::AnalyzersCache] Unable to get NuGet interfaces. No exception thrown");
            }
            else
            {
                lifetime.AddBracket(
                    () =>
                {
                    this.packageInstallerEvents.PackageInstalled   += this.ResetAnalyzersCache;
                    this.packageInstallerEvents.PackageUninstalled += this.ResetAnalyzersCache;
                },
                    () =>
                {
                    this.packageInstallerEvents.PackageInstalled   -= this.ResetAnalyzersCache;
                    this.packageInstallerEvents.PackageUninstalled -= this.ResetAnalyzersCache;
                });
                solutionLoadTasksScheduler.EnqueueTask(new SolutionLoadTask("StyleCop.ReferencedAnalyzersCache", SolutionLoadTaskKinds.AfterDone,
                                                                            () =>
                {
                    this.ResetAnalyzersCache(null);
                }));
            }
        }
        public MetaFileTracker(Lifetime lifetime, ChangeManager changeManager, ISolution solution, ILogger logger, 
            ISolutionLoadTasksScheduler solutionLoadTasksScheduler,
            UnitySolutionTracker unitySolutionTracker)
        {
            mySolution = solution;
            myLogger = logger;

            solutionLoadTasksScheduler.EnqueueTask(new SolutionLoadTask("AdviseForChanges", SolutionLoadTaskKinds.AfterDone,
                () =>
                {
                    if (!unitySolutionTracker.IsUnityGeneratedProject.Value)
                        return;
                    
                    changeManager.RegisterChangeProvider(lifetime, this);
                    changeManager.AddDependency(lifetime, this, solution);
                }));
        }
Ejemplo n.º 8
0
        public UnityExternalFilesModuleProcessor(Lifetime lifetime, ILogger logger, ISolution solution,
                                                 ChangeManager changeManager,
                                                 IShellLocks locks,
                                                 ISolutionLoadTasksScheduler scheduler,
                                                 IFileSystemTracker fileSystemTracker,
                                                 ProjectFilePropertiesFactory projectFilePropertiesFactory,
                                                 UnityYamlPsiSourceFileFactory psiSourceFileFactory,
                                                 UnityExternalFilesModuleFactory moduleFactory,
                                                 UnityYamlDisableStrategy unityYamlDisableStrategy,
                                                 BinaryUnityFileCache binaryUnityFileCache,
                                                 ISettingsSchema settingsSchema,
                                                 SettingsLayersProvider settingsLayersProvider,
                                                 AssetSerializationMode assetSerializationMode,
                                                 UnityYamlSupport unityYamlSupport)
        {
            myLifetime                     = lifetime;
            myLogger                       = logger;
            mySolution                     = solution;
            myChangeManager                = changeManager;
            myLocks                        = locks;
            myFileSystemTracker            = fileSystemTracker;
            myProjectFilePropertiesFactory = projectFilePropertiesFactory;
            myPsiSourceFileFactory         = psiSourceFileFactory;
            myModuleFactory                = moduleFactory;
            myUnityYamlDisableStrategy     = unityYamlDisableStrategy;
            myBinaryUnityFileCache         = binaryUnityFileCache;
            mySettingsSchema               = settingsSchema;
            mySettingsLayersProvider       = settingsLayersProvider;
            myAssetSerializationMode       = assetSerializationMode;
            myUnityYamlSupport             = unityYamlSupport;

            changeManager.RegisterChangeProvider(lifetime, this);

            myRootPaths = new JetHashSet <FileSystemPath>();

            // SolutionDirectory isn't absolute in tests, and will throw an exception if we use it when we call Exists
            mySolutionDirectory = solution.SolutionDirectory;
            if (!mySolutionDirectory.IsAbsolute)
            {
                mySolutionDirectory = solution.SolutionDirectory.ToAbsolutePath(FileSystemUtil.GetCurrentDirectory());
            }

            scheduler.EnqueueTask(new SolutionLoadTask(GetType().Name + ".Activate",
                                                       SolutionLoadTaskKinds.PreparePsiModules,
                                                       () => myChangeManager.AddDependency(myLifetime, mySolution.PsiModules(), this)));
        }
Ejemplo n.º 9
0
 public SolutionTracker(ISolution solution, ISolutionLoadTasksScheduler solutionLoadTasksScheduler, IAnalyticsTransmitter transmitter)
 {
     solutionLoadTasksScheduler.EnqueueTask(new SolutionLoadTask("SpecFlow", SolutionLoadTaskKinds.Done, () =>
     {
         var projects = ((SolutionElement)solution).GetAllProjects();
         foreach (var project in projects)
         {
             var targetFrameworks = project.TargetFrameworkIds;
             var assemblies       = project.GetModuleReferences(targetFrameworks.First());
             if (assemblies.Any(a => a.Name == "TechTalk.SpecFlow"))
             {
                 transmitter.TransmitRuntimeEvent(new GenericEvent("Rider SpecFlow loaded", new Dictionary <string, string>()
                 {
                     { "ProjectTargetFramework", string.Join(";", targetFrameworks.Select(t => t.PresentableString)) }
                 }));
             }
         }
     }
                                                                 ));
 }
        public DeferredCacheController(Lifetime lifetime, ISolution solution, SolutionCaches solutionCaches,
                                       ISolutionLoadTasksScheduler tasksScheduler, IPersistentIndexManager persistentIndexManager, IPsiFiles psiFiles,
                                       SolutionAnalysisConfiguration solutionAnalysisConfiguration, IShellLocks shellLocks,
                                       DeferredHelperCache deferredHelperCache, IEnumerable <IDeferredCache> deferredCaches,
                                       DeferredCacheProgressBar progressBar, ILogger logger)
        {
            myLifetime       = lifetime;
            mySolution       = solution;
            mySolutionCaches = solutionCaches;
            myPsiFiles       = psiFiles;
            mySolutionAnalysisConfiguration = solutionAnalysisConfiguration;
            myShellLocks          = shellLocks;
            myDeferredHelperCache = deferredHelperCache;
            myDeferredCaches      = deferredCaches;
            myProgressBar         = progressBar;
            myLogger = logger;
            var defaultValue = solutionCaches.PersistentProperties.TryGetValue("DeferredCachesCompletedOnce", out var result) && result.Equals("True");

            myCompletedOnce = new ViewableProperty <bool>(defaultValue);

            myGroupingEvent = solution.Locks.GroupingEvents.CreateEvent(lifetime, "DeferredCachesCoreActivity", TimeSpan.FromMilliseconds(500), Rgc.Guarded, RunBackgroundActivity);
        }
 public CgIncludeDirectoryTracker(Lifetime lifetime, UnityReferencesTracker unityReferencesTracker,
                                  SolutionCaches solutionCaches, IShellLocks shellLocks, ISolutionLoadTasksScheduler scheduler,
                                  CppGlobalCacheImpl cppGlobalCache, UnityVersion unityVersion, ILogger logger)
 {
     scheduler.EnqueueTask(new SolutionLoadTask("InitCgIncludeDirectoryTracker", SolutionLoadTaskKinds.PreparePsiModules,
                                                () =>
     {
         unityReferencesTracker.HasUnityReference.AdviseOnce(lifetime, _ =>
         {
             if (solutionCaches.PersistentProperties.TryGetValue(CG_INCLUDE_DIRECTORY_PATH, out var result))
             {
                 var oldPath = FileSystemPath.TryParse(result, FileSystemPathInternStrategy.INTERN);
                 var newPath = GetCgIncludeFolderPath(unityVersion);
                 if (!oldPath.Equals(newPath))
                 {
                     cppGlobalCache.IsCacheStarted.Change.Advise(lifetime, v =>
                     {
                         if (v.HasNew && v.New)
                         {
                             shellLocks.Tasks.StartNew(lifetime, Scheduling.MainGuard, TaskPriority.High, () =>
                             {
                                 logger.Verbose("Dropping C++ cache, because Unity version is changed");
                                 cppGlobalCache.ResetCache();
                                 solutionCaches.PersistentProperties[CG_INCLUDE_DIRECTORY_PATH] = newPath.FullPath;
                             });
                         }
                     });
                 }
             }
             else
             {
                 solutionCaches.PersistentProperties[CG_INCLUDE_DIRECTORY_PATH] = GetCgIncludeFolderPath(unityVersion).FullPath;
             }
         });
     }));
 }
Ejemplo n.º 12
0
        public MonoInstallTrigger(Lifetime lifetime, ILogger logger, ISolutionLoadTasksScheduler scheduler,
                                  ISolution solution, UnitySolutionTracker unitySolutionTracker, UnityHost host,
                                  NotificationsModel notificationsModel)
        {
            if (PlatformUtil.RuntimePlatform == PlatformUtil.Platform.Windows)
            {
                return;
            }

            scheduler.EnqueueTask(new SolutionLoadTask("Check mono runtime", SolutionLoadTaskKinds.AfterDone, () =>
            {
                if (!unitySolutionTracker.IsUnityGeneratedProject.Value)
                {
                    return;
                }

                if (!HasModernUnityProjects(solution))
                {
                    return;
                }

                solution.Locks.Tasks.Queue(lifetime, () =>
                {
                    var wellKnownMonoRuntimes = MonoRuntimeDetector.DetectWellKnownMonoRuntimes();
                    var installedValidMono    = wellKnownMonoRuntimes
                                                .Any(runtime =>
                    {
                        var parsedVersion = string.Empty;
                        try
                        {
                            parsedVersion = ProcessOutputUtil.ExtractMonoVersion(runtime.ExePath);
                        }
                        catch (Exception e)
                        {
                            logger.Warn(e);
                        }

                        // if we fail to parse version - consider it is old
                        if (Version.TryParse(parsedVersion, out var version))
                        {
                            return(version >= new Version(5, 16));    // mono 5.16+ supports C# 7.3
                        }
                        logger.Warn("Failed to parse ProcessOutputUtil.ExtractMonoVersion output.");
                        return(false);
                    });

                    if (installedValidMono)
                    {
                        return;
                    }

                    if (PlatformUtil.RuntimePlatform == PlatformUtil.Platform.MacOsX)
                    {
                        solution.Locks.ExecuteOrQueue(lifetime, "Show install mono dialog",
                                                      () => { host.PerformModelAction(model => model.ShowInstallMonoDialog()); });
                    }
                    else if (PlatformUtil.RuntimePlatform == PlatformUtil.Platform.Linux)
                    {
                        var notification = new NotificationModel("Mono 5.16+ is required",
                                                                 "<html>Project requires new Mono with MSBuild for new C# language features support.<br>" +
                                                                 RiderContextNotificationHelper.MakeOpenSettingsLink(
                                                                     WellKnownSettingPages.Environment,
                                                                     "Install the latest Mono")
                                                                 + ".<br>" +
                                                                 "If a Mono runtime is available in a non-standard location, please " +
                                                                 RiderContextNotificationHelper.MakeOpenSettingsLink(
                                                                     WellKnownSettingPages.ToolsetAndBuild,
                                                                     "specify the custom runtime location in settings")
                                                                 + ".</html>"

                                                                 , true,
                                                                 RdNotificationEntryType.WARN);
                        solution.Locks.ExecuteOrQueue(lifetime, "MonoInstallTrigger.Notify", () => notificationsModel.Notification(notification));
                    }
                });
            }));
        }
Ejemplo n.º 13
0
 public TestUnityExternalFilesModuleProcessor(Lifetime lifetime, ILogger logger, ISolution solution, ChangeManager changeManager, IShellLocks locks, ISolutionLoadTasksScheduler scheduler, IFileSystemTracker fileSystemTracker, ProjectFilePropertiesFactory projectFilePropertiesFactory, UnityYamlPsiSourceFileFactory psiSourceFileFactory, UnityExternalFilesModuleFactory moduleFactory, UnityYamlDisableStrategy unityYamlDisableStrategy, ISettingsSchema settingsSchema, SettingsLayersProvider settingsLayersProvider, AssetSerializationMode assetSerializationMode)
     : base(lifetime, logger, solution, changeManager, locks, scheduler, fileSystemTracker, projectFilePropertiesFactory, psiSourceFileFactory, moduleFactory, unityYamlDisableStrategy, settingsSchema, settingsLayersProvider)
 {
 }
 public TestUnityExternalFilesModuleProcessor(Lifetime lifetime, ILogger logger, ISolution solution, ChangeManager changeManager, IShellLocks locks, ISolutionLoadTasksScheduler scheduler, IFileSystemTracker fileSystemTracker, ProjectFilePropertiesFactory projectFilePropertiesFactory, UnityYamlPsiSourceFileFactory psiSourceFileFactory, UnityExternalFilesModuleFactory moduleFactory, UnityYamlDisableStrategy unityYamlDisableStrategy)
     : base(lifetime, logger, solution, changeManager, locks, scheduler, fileSystemTracker, projectFilePropertiesFactory, psiSourceFileFactory, moduleFactory, unityYamlDisableStrategy)
 {
 }
Ejemplo n.º 15
0
        public UnrealPluginDetector(Lifetime lifetime, ILogger logger,
                                    CppUE4SolutionDetector solutionDetector, ISolution solution,
                                    IShellLocks locks, ISolutionLoadTasksScheduler scheduler)
        {
            myLifetime          = lifetime;
            InstallInfoProperty =
                new Property <UnrealPluginInstallInfo>(myLifetime, "UnrealPlugin.InstallInfoNotification", null, true);
            myLogger           = logger;
            mySolution         = solution;
            mySolutionDetector = solutionDetector;

            mySolutionDetector.IsUE4Solution_Observable.Change.Advise_When(myLifetime,
                                                                           newValue => newValue == TriBool.True, _ =>
            {
                scheduler.EnqueueTask(new SolutionLoadTask("Find installed RiderLink plugins",
                                                           SolutionLoadTaskKinds.Done,
                                                           () =>
                {
                    myLogger.Info("[UnrealLink]: Looking for RiderLink plugins");
                    myUnrealVersion = mySolutionDetector.Version;

                    if (myUnrealVersion < myMinimalSupportedVersion)
                    {
                        locks.ExecuteOrQueue(myLifetime, "UnrealLink.CheckSupportedVersion",
                                             () =>
                        {
                            var notification =
                                new NotificationModel(
                                    $"Unreal Engine {myMinimalSupportedVersion}+ is required",
                                    $"<html>UnrealLink supports Unreal Engine versions starting with {myMinimalSupportedVersion}<br>" +
                                    "<b>WARNING: Advanced users only</b><br>" +
                                    "You can manually download the latest version of plugin and build It for your version of Unreal Editor<br>" +
                                    RiderContextNotificationHelper.MakeLink(
                                        "https://github.com/JetBrains/UnrealLink/releases/latest",
                                        "Download latest Unreal Editor plugin") +
                                    "</html>",
                                    true,
                                    RdNotificationEntryType.WARN,
                                    new List <NotificationHyperlink>());
                            var notificationsModel = Shell.Instance.GetComponent <NotificationsModel>();
                            notificationsModel.Notification(notification);
                        });
                        return;
                    }

                    var installInfo       = new UnrealPluginInstallInfo();
                    var foundEnginePlugin = TryGetEnginePluginFromSolution(solutionDetector, installInfo);
                    ISet <FileSystemPath> uprojectLocations;
                    using (solution.Locks.UsingReadLock())
                    {
                        var allProjects = mySolution.GetAllProjects();
                        if (solutionDetector.SupportRiderProjectModel ==
                            CppUE4ProjectModelSupportMode.UprojectOpened)
                        {
                            uprojectLocations = allProjects.Where(project =>
                            {
                                if (project.IsMiscProjectItem() || project.IsMiscFilesProject())
                                {
                                    return(false);
                                }

                                var location = project.Location;
                                if (location == null)
                                {
                                    return(false);
                                }

                                if (EXCLUDED_PROJECTS.Contains(location.NameWithoutExtension))
                                {
                                    return(false);
                                }

                                // TODO: drop this ugly check after updating to net211 where Location == "path/to/game.uproject"
                                var isUproject =
                                    location.ExistsFile && location.ExtensionNoDot == UPROJECT_FILE_FORMAT &&
                                    location.NameWithoutExtension == project.Name;
                                return(isUproject || (location / $"{location.Name}.uproject").ExistsFile);
                            }).Select(project =>
                            {
                                var location = project.Location;
                                if (location.ExistsFile)
                                {
                                    return(location);
                                }
                                return(location / $"{location.Name}.uproject");
                            }).ToSet();
                        }
                        else
                        {
                            uprojectLocations = allProjects.SelectMany(project =>
                                                                       project.GetAllProjectFiles(projectFile =>
                            {
                                var location = projectFile.Location;
                                if (location == null || !location.ExistsFile)
                                {
                                    return(false);
                                }

                                return(location.ExtensionNoDot == UPROJECT_FILE_FORMAT &&
                                       location.NameWithoutExtension == project.Name);
                            })).Select(file => file.Location).ToSet();
                        }
                    }

                    myLogger.Info($"[UnrealLink]: Found {uprojectLocations.Count} uprojects");

                    if (!foundEnginePlugin && !uprojectLocations.IsEmpty())
                    {
                        // All projects in the solution are bound to the same engine
                        // So take first project and use it to find Unreal Engine
                        TryGetEnginePluginFromUproject(uprojectLocations.FirstNotNull(), installInfo);
                        foundEnginePlugin = installInfo.EnginePlugin.IsPluginAvailable;
                    }

                    // Gather data about Project plugins
                    foreach (var uprojectLocation in uprojectLocations)
                    {
                        myLogger.Info($"[UnrealLink]: Looking for plugin in {uprojectLocation}");
                        var projectPlugin = GetProjectPluginForUproject(uprojectLocation);
                        if (projectPlugin.IsPluginAvailable)
                        {
                            myLogger.Info(
                                $"[UnrealLink]: found plugin {projectPlugin.UnrealPluginRootFolder}");
                        }

                        installInfo.ProjectPlugins.Add(projectPlugin);
                    }

                    if (foundEnginePlugin)
                    {
                        installInfo.Location = PluginInstallLocation.Engine;
                    }
                    else if (installInfo.ProjectPlugins.Any(description => description.IsPluginAvailable))
                    {
                        installInfo.Location = PluginInstallLocation.Game;
                    }
                    else
                    {
                        installInfo.Location = PluginInstallLocation.NotInstalled;
                    }
                    InstallInfoProperty.SetValue(installInfo);
                }));
            });
        }