private bool InstallPlugin()

in src/dotnet/RiderPlugin.UnrealLink/PluginInstaller/UnrealPluginInstaller.cs [369:480]


        private bool InstallPlugin(Lifetime lifetime,
            UnrealPluginInstallInfo.InstallDescription installDescription,
            VirtualFileSystemPath engineRoot, IProperty<double> progressProperty, double range)
        {
            using var def = new LifetimeDefinition();
            var ZIP_STEP = 0.1 * range;
            var PATCH_STEP = 0.1 * range;
            var BUILD_STEP = 0.7 * range;

            var pluginRootFolder = installDescription.UnrealPluginRootFolder;

            var editorPluginPathFile = myPathsProvider.PathToPackedPlugin;
            var pluginTmpDir = CreateTempDirectory();
            if (pluginTmpDir.IsNullOrEmpty()) return false;
            if (PlatformUtil.RuntimePlatform == JetPlatform.Windows && pluginTmpDir.FullPath.Any(c => c >= 128))
            {
                string nonAsciiCharactersText = Strings.NonASCIICharactersInTheBuildDirectory_Text;

                myUnrealHost.myModel.RiderLinkInstallMessage(new InstallMessage(nonAsciiCharactersText, ContentType.Error));
            }
            
            def.Lifetime.OnTermination(() => { pluginTmpDir.Delete(); });
            try
            {
                ZipFile.ExtractToDirectory(editorPluginPathFile.FullPath, pluginTmpDir.FullPath);
                progressProperty.Value += ZIP_STEP;
            }
            catch (Exception exception)
            {
                myLogger.Warn(exception, $"[UnrealLink]: Couldn't extract {editorPluginPathFile} to {pluginTmpDir}");

                const string unzipFailTitle = "Failed to unzip new RiderLink plugin";
                var unzipFailText =
                    $"Failed to unzip new version of RiderLink ({editorPluginPathFile.FullPath}) to user folder ({pluginTmpDir.FullPath})\n" +
                    "Try restarting Rider in administrative mode";

                myUnrealHost.myModel.RiderLinkInstallMessage(new InstallMessage(unzipFailTitle, ContentType.Error));
                myUnrealHost.myModel.RiderLinkInstallMessage(new InstallMessage(unzipFailText, ContentType.Error));
                return false;
            }

            lifetime.ToCancellationToken().ThrowIfCancellationRequested();

            var upluginFile = UnrealPluginDetector.GetPathToUpluginFile(pluginTmpDir);
            var pluginBuildOutput = CreateTempDirectory();
            if (pluginBuildOutput.IsNullOrEmpty()) return false;
            
            def.Lifetime.OnTermination(() => { pluginBuildOutput.Delete(); });
            var buildProgress = progressProperty.Value;
            var isPluginBuilt = BuildPlugin(lifetime, upluginFile, pluginBuildOutput,
                engineRoot, value => progressProperty.SetValue(buildProgress + value * BUILD_STEP));
            if (!isPluginBuilt)
            {
                myLogger.Error($"Failed to build RiderLink for any available project");
                myUnrealHost.myModel.RiderLinkInstallMessage(new InstallMessage(Strings.FailedToBuildRiderLinkPlugin_Text, ContentType.Error));
                return false;
            }

            progressProperty.Value = buildProgress + BUILD_STEP;

            lifetime.ToCancellationToken().ThrowIfCancellationRequested();

            if (!PatchUpluginFileAfterInstallation(pluginBuildOutput))
            {
                var failedToPatch = Strings.FailedToPatchRiderLinkUplugin_Text;
                var failedPatchText = Strings.FailedToPatchRiderLinkUplugin_Message;
                myUnrealHost.myModel.RiderLinkInstallMessage(new InstallMessage(failedToPatch, ContentType.Normal));
                myUnrealHost.myModel.RiderLinkInstallMessage(new InstallMessage(failedPatchText, ContentType.Normal));
            }

            progressProperty.Value += PATCH_STEP;

            lifetime.ToCancellationToken().ThrowIfCancellationRequested();

            pluginRootFolder.CreateDirectory().DeleteChildren();
            pluginBuildOutput.Copy(pluginRootFolder);

            installDescription.IsPluginAvailable = true;
            installDescription.PluginChecksum = myPathsProvider.CurrentPluginChecksum;

            var title = Strings.RiderLinkPluginInstalled_Title;
            var text = Strings.RiderLinkPluginInstalled_Message.Format(pluginRootFolder);

            myUnrealHost.myModel.RiderLinkInstallMessage(new InstallMessage(title, ContentType.Normal));
            myUnrealHost.myModel.RiderLinkInstallMessage(new InstallMessage(text, ContentType.Normal));

            var notification = new NotificationModel(mySolution.GetRdProjectId(), title, text, true,
              RdNotificationEntryType.INFO, new List<NotificationHyperlink>());

            mySolution.Locks.ExecuteOrQueue(Lifetime, "UnrealLink.InstallPlugin",
                () => { myNotificationsModel.Notification(notification); });

            var cppUe4SolutionDetector = mySolution.GetComponent<ICppUE4SolutionDetector>();
            var isSln  = cppUe4SolutionDetector.SupportRiderProjectModel != CppUE4ProjectModelSupportMode.UprojectOpened;
            if (isSln)
            {
                var refreshText = Strings.RefreshingProjectFiles_Text;
                myUnrealHost.myModel.RiderLinkInstallMessage(new InstallMessage(refreshText, ContentType.Normal));
                mySolution.Locks.ExecuteOrQueue(Lifetime, Strings.RefreshProjectsAfterRiderLinkInstallation_Text, () => 
                    UnrealProjectsRefresher.RefreshProjects(Lifetime, mySolution, installDescription, engineRoot));
            } else {
                var actionTitle = "Update VirtualFileSystem after RiderLink installation";
                mySolution.Locks.Queue(Lifetime, actionTitle, () =>
                {
                    myLogger.Verbose(actionTitle);
                    var fileSystemModel = mySolution.GetProtocolSolution().GetFileSystemModel();
                    fileSystemModel.RefreshPaths.Start(lifetime,
                        new RdFsRefreshRequest(new List<RdPath>() { pluginRootFolder.ToRd() }, true));
                });
            }
            return true;
        }