예제 #1
0
        private static string SafelyCreateLogFileWithFallback(ProjectUpgradeLogger upgradeLogger, string basePath)
        {
            string str = UpgradeWizard.SafelyCreateLogFile(upgradeLogger, basePath);

            if (!string.IsNullOrEmpty(str))
            {
                return(str);
            }
            DateTime    now = DateTime.Now;
            string      fileNameWithoutExtension = Path.GetFileNameWithoutExtension(basePath);
            CultureInfo invariantCulture         = CultureInfo.InvariantCulture;

            object[] year = new object[] { fileNameWithoutExtension, now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second };
            string   str1 = string.Format(invariantCulture, "{0}.{1}-{2}-{3}_{4}-{5}-{6}", year);

            str1 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), str1);
            str  = UpgradeWizard.SafelyCreateLogFile(upgradeLogger, str1);
            if (!string.IsNullOrEmpty(str))
            {
                return(str);
            }
            str = UpgradeWizard.SafelyCreateLogFile(upgradeLogger, Path.GetTempFileName());
            if (!string.IsNullOrEmpty(str))
            {
                return(str);
            }
            return(null);
        }
예제 #2
0
        public static void SaveLogAndPromptUser(ProjectUpgradeLogger upgradeLogger, IServiceProvider serviceProvider, string basePath, bool success)
        {
            if (upgradeLogger.IsEmpty)
            {
                return;
            }
            string str = UpgradeWizard.SafelyCreateLogFileWithFallback(upgradeLogger, basePath);

            if (string.IsNullOrEmpty(str))
            {
                return;
            }
            success = success & !upgradeLogger.HasErrors;
            if (!success)
            {
                IMessageDisplayService service        = (IMessageDisplayService)serviceProvider.GetService(typeof(IMessageDisplayService));
                MessageBoxArgs         messageBoxArg  = new MessageBoxArgs();
                CultureInfo            currentCulture = CultureInfo.CurrentCulture;
                string   upgradeErrorsMessage         = StringTable.UpgradeErrorsMessage;
                object[] objArray = new object[] { basePath };
                messageBoxArg.Message          = string.Format(currentCulture, upgradeErrorsMessage, objArray);
                messageBoxArg.HyperlinkMessage = StringTable.UpgradeErrorsLinkMessage;
                messageBoxArg.HyperlinkUri     = new Uri(str, UriKind.Absolute);
                messageBoxArg.Button           = MessageBoxButton.OK;
                messageBoxArg.Image            = MessageBoxImage.Hand;
                messageBoxArg.AutomationId     = "UpgradeWarningDialog";
                service.ShowMessage(messageBoxArg);
            }
        }
예제 #3
0
        private static string SafelyCreateLogFile(ProjectUpgradeLogger upgradeLogger, string pathBase)
        {
            string str;
            string str1 = ".upgrade_log.txt";
            string str2 = string.Concat(pathBase, str1);

            for (int i = 1; i < 10000 && File.Exists(str2); i++)
            {
                object[] objArray = new object[] { pathBase, ".", i, str1 };
                str2 = string.Concat(objArray);
            }
            if (File.Exists(str2))
            {
                return(null);
            }
            try
            {
                using (StreamWriter streamWriter = File.CreateText(str2))
                {
                    upgradeLogger.Save(streamWriter);
                }
                str = str2;
            }
            catch (Exception exception)
            {
                return(null);
            }
            return(str);
        }
예제 #4
0
        public bool Upgrade()
        {
            bool?nullable;

            if (ConversionSupressor.IsSupressed)
            {
                return(true);
            }
            bool   hasErrors = false;
            string str       = null;

            UpgradeWizard.UpgradeResponse upgrade = this.converter.PromptToUpgrade(this.versionMapping, out nullable, ref str, out this.proposedUpgrades);
            if (upgrade != UpgradeWizard.UpgradeResponse.Upgrade)
            {
                hasErrors = upgrade == UpgradeWizard.UpgradeResponse.DontUpgrade;
            }
            else
            {
                using (ProjectUpgradeLogger projectUpgradeLogger = new ProjectUpgradeLogger())
                {
                    hasErrors = true;
                    using (IDisposable disposable = TemporaryCursor.SetWaitCursor())
                    {
                        foreach (UpgradeAction proposedUpgrade in this.proposedUpgrades)
                        {
                            if (proposedUpgrade.DoUpgrade())
                            {
                                continue;
                            }
                            hasErrors = false;
                        }
                    }
                    hasErrors = hasErrors & !projectUpgradeLogger.HasErrors;
                    if (hasErrors && this.solutionUpgradedAction != null)
                    {
                        this.solutionUpgradedAction();
                    }
                    if (hasErrors && !string.IsNullOrEmpty(str))
                    {
                        MessageBoxArgs messageBoxArg = new MessageBoxArgs()
                        {
                            Message          = StringTable.UpgradeUpgradeAndBackupSuccess,
                            Button           = MessageBoxButton.OK,
                            Image            = MessageBoxImage.Asterisk,
                            AutomationId     = "BackupAndUpgradeCompletedDialog",
                            HyperlinkMessage = StringTable.UpgradeBackupFolderLink,
                            HyperlinkUri     = new Uri(str)
                        };
                        this.serviceProvider.MessageDisplayService().ShowMessage(messageBoxArg);
                    }
                    UpgradeWizard.SaveLogAndPromptUser(projectUpgradeLogger, this.serviceProvider, this.solution.DocumentReference.Path, hasErrors);
                }
            }
            if (nullable.HasValue && nullable.Value)
            {
                this.converter.IsEnabled = false;
            }
            return(hasErrors);
        }
예제 #5
0
 public override void Execute()
 {
     this.HandleBasicExceptions(() => {
         using (ProjectUpgradeLogger projectUpgradeLogger = new ProjectUpgradeLogger())
         {
             IProject project = this.SelectedProjectOrNull();
             ISolutionManagement solutionManagement = this.Solution() as ISolutionManagement;
             if (base.Services.PromptUserYesNo(StringTable.UpgradeProjectWarning))
             {
                 if (this.SaveSolution(true))
                 {
                     if (this.SaveSolution(true))
                     {
                         DocumentReference documentReference = project.DocumentReference;
                         solutionManagement.CloseProject(project);
                         IProjectStore projectStore = null;
                         try
                         {
                             projectStore = ProjectStoreHelper.CreateProjectStore(documentReference, base.Services, ProjectStoreHelper.DefaultProjectCreationChain);
                             using (IDisposable disposable = this.SuspendWatchers())
                             {
                                 if (this.converter.Convert(new ConversionTarget(projectStore), this.sourceType, this.targetType))
                                 {
                                     using (IDisposable disposable1 = projectUpgradeLogger.SuspendLogging())
                                     {
                                         projectStore.Dispose();
                                         projectStore = ProjectStoreHelper.CreateProjectStore(documentReference, base.Services, ProjectStoreHelper.DefaultProjectCreationChain);
                                         if (solutionManagement.AddProject(projectStore) == null)
                                         {
                                             projectStore.Dispose();
                                         }
                                     }
                                     solutionManagement.OpenInitialViews();
                                 }
                                 else
                                 {
                                     projectStore.Dispose();
                                     return;
                                 }
                             }
                             UpgradeWizard.SaveLogAndPromptUser(projectUpgradeLogger, base.Services, solutionManagement.DocumentReference.Path, true);
                         }
                         catch
                         {
                             if (projectStore != null)
                             {
                                 projectStore.Dispose();
                             }
                             UpgradeWizard.SaveLogAndPromptUser(projectUpgradeLogger, base.Services, solutionManagement.DocumentReference.Path, false);
                             throw;
                         }
                     }
                 }
             }
         }
     });
 }
예제 #6
0
        /// <summary>
        /// Performs in-memory conversion of the project with a given path
        /// </summary>
        /// <returns>Root element of the converted project or <c>null</c> if conversion failed.</returns>
        private ProjectRootElement ConvertProject(string projectFileName, ProjectUpgradeLogger logger)
        {
            var projectConverter = new Microsoft.Build.Conversion.ProjectFileConverter();

            projectConverter.OldProjectFile = projectFileName;
            projectConverter.NewProjectFile = projectFileName;
            ProjectRootElement convertedProject = null;

            try
            {
                convertedProject = projectConverter.ConvertInMemory();
            }
            catch (Exception ex)
            {
                logger.LogInfo(ex.Message);
            }
            return(convertedProject);
        }
 /// <summary>
 /// Performs in-memory conversion of the project with a given path
 /// </summary>
 /// <returns>Root element of the converted project or <c>null</c> if conversion failed.</returns>
 private ProjectRootElement ConvertProject(string projectFileName, ProjectUpgradeLogger logger)
 {
     var projectConverter = new Microsoft.Build.Conversion.ProjectFileConverter();
     projectConverter.OldProjectFile = projectFileName;
     projectConverter.NewProjectFile = projectFileName;
     ProjectRootElement convertedProject = null;
     try
     {
         convertedProject = projectConverter.ConvertInMemory();
     }
     catch (Exception ex)
     {
         logger.LogInfo(ex.Message);
     }
     return convertedProject;
 }
        private void BackupProjectFilesIfNeeded(
            string projectFilePath, 
            ProjectUpgradeLogger logger, 
            __VSPPROJECTUPGRADEVIAFACTORYFLAGS flag, 
            string copyLocation, 
            ProjectRootElement convertedProject
            )
        {
            var projectName = Path.GetFileNameWithoutExtension(projectFilePath);
            var projectFileName = Path.GetFileName(projectFilePath);

            if (HasCopyBackupFlag(flag) || HasSxSBackupFlag(flag))
            {
                if (HasSxSBackupFlag(flag) && !Directory.Exists(copyLocation))
                {
                    Debug.Assert(false, "Env should create the directory for us");
                    throw new ProjectUpgradeFailedException();
                }

                // copy project file
                {
                    var targetFilePath = Path.Combine(copyLocation, projectFileName);
                    if (HasSxSBackupFlag(flag))
                    {
                        bool ignored;
                        targetFilePath = GetUniqueFileName(targetFilePath + ".old", out ignored);
                    }

                    try
                    {
                        File.Copy(projectFilePath, targetFilePath);
                        logger.LogInfo(SR.GetString(SR.ProjectBackupSuccessful, targetFilePath));
                    }
                    catch (Exception ex)
                    {
                        var message = SR.GetString(SR.ErrorMakingProjectBackup, targetFilePath);
                        throw new ProjectUpgradeFailedException(string.Format("{0} : {1}", message, ex.Message));
                    }
                }

                if (HasCopyBackupFlag(flag))
                {
                    //Now iterate through the project items and copy them to the new location
                    //All projects under the solution retain its folder hierarchy
                    var types = new[] { "Compile", "None", "Content", "EmbeddedResource", "Resource", "BaseApplicationManifest", "ApplicationDefinition", "Page" };

                    var metadataLookup =
                            convertedProject
                            .Items
                            .GroupBy(i => i.ItemType)
                            .ToDictionary(x => x.Key);

                    var sourceProjectDir = Path.GetDirectoryName(projectFilePath);
                    foreach (var ty in types)
                    {
                        if (metadataLookup.ContainsKey(ty))
                        {
                            foreach (var item in metadataLookup[ty])
                            {
                                var linkMetadataElement = item.Metadata.FirstOrDefault(me => me.Name == "Link");
                                string linked = linkMetadataElement != null && !string.IsNullOrEmpty(linkMetadataElement.Value) ? linkMetadataElement.Value : null;
                                
                                var include = item.Include;

                                Debug.Assert(!string.IsNullOrEmpty(include));

                                string sourceFilePath;

                                var targetFileName = Path.Combine(copyLocation, linked ?? include);

                                if (Path.IsPathRooted(include))
                                {
                                    //if the path is fully qualified already, then just use it
                                    sourceFilePath = include;
                                }
                                else
                                {
                                    //otherwise tack the filename on to the path
                                    sourceFilePath = Path.Combine(sourceProjectDir, include);
                                }
                                if (linked != null && include[0] == '.')
                                {
                                    //if linked file up a level (or more), then turn it into a path without the ..\ in the middle
                                    sourceFilePath = Path.GetFullPath(sourceFilePath);
                                }

                                bool initiallyUnique;
                                targetFileName = GetUniqueFileName(targetFileName, out initiallyUnique);
                                if (!initiallyUnique)
                                {
                                    logger.LogInfo(SR.GetString(SR.BackupNameConflict, targetFileName));
                                }

                                //Warn user in upgrade log if linked files are used "project may not build"
                                if (linked != null && HasCopyBackupFlag(flag))
                                {
                                    logger.LogWarning(SR.GetString(SR.ProjectContainsLinkedFile, targetFileName));
                                }

                                // ensure target folder exists
                                Directory.CreateDirectory(Path.GetDirectoryName(targetFileName));

                                try
                                {
                                    File.Copy(sourceFilePath, targetFileName);
                                    logger.LogInfo(SR.GetString(SR.BackupSuccessful, targetFileName));
                                }
                                catch (Exception ex)
                                {
                                    var message = SR.GetString(SR.ErrorMakingBackup, targetFileName);
                                    logger.LogError(string.Format("{0} : {1}", message, ex.Message));
                                }                                
                            }
                        }
                    }
                }
            }
        }
        public virtual int UpgradeProject(
            string projectFilePath, 
            uint upgradeFlag, 
            string initialCopyLocation, 
            out string upgradeFullyQualifiedFileName, 
            IVsUpgradeLogger upgradeLogger, 
            out int upgradeRequired,
            out Guid newProjectFactory
            )
        {
            // initialize out params in case of failure
            upgradeFullyQualifiedFileName = null;
            upgradeRequired = 0;
            newProjectFactory = Guid.Empty;

            __VSPPROJECTUPGRADEVIAFACTORYFLAGS flag;
            string copyLocation = initialCopyLocation;
            var r = NormalizeUpgradeFlag(upgradeFlag, out flag, ref copyLocation);
            if (r != VSConstants.S_OK)
            {
                return r;
            }

            string projectName = Path.GetFileNameWithoutExtension(projectFilePath);
            var logger = new ProjectUpgradeLogger(upgradeLogger, projectName, projectFilePath);

            uint ignore;
            ((IVsProjectUpgradeViaFactory)this).UpgradeProject_CheckOnly(projectFilePath, upgradeLogger, out upgradeRequired, out newProjectFactory, out ignore);

            // no upgrade required and not 'copy-backup'
            if (upgradeRequired == 0 && !HasCopyBackupFlag(flag))
            {
                //Write an informational message "No upgrade required for project foo"?
                logger.LogInfo(SR.GetString(SR.ProjectConversionNotRequired));
                logger.LogInfo(SR.GetString(SR.ConversionNotRequired));

                upgradeFullyQualifiedFileName = projectFilePath;
                return VSConstants.S_OK;
            }

            // upgrade is not required but backup may still be needed

            var projectFileName = Path.GetFileName(projectFilePath);
            upgradeFullyQualifiedFileName = projectFilePath;

            if (HasSxSBackupFlag(flag))
            {
                // for SxS call use location near the original file
                copyLocation = Path.GetDirectoryName(projectFilePath);
            }

            // workflow is taken from vsprjfactory.cpp (vsproject\vsproject)
            // 1. convert the project (in-memory)
            // 2. save SCC related info
            // 3. use data stored on step 2 in GetSccInfo calls (during QueryEditFiles)
            // 4. if succeeded - save project on disk
            // F# doesn't use .user file so all related code is skipped
            try
            {
                // load MSBuild project in memory: this will be needed in all cases not depending whether upgrade is required or not
                // we use this project to determine the set of files to copy
                ProjectRootElement convertedProject = ConvertProject(projectFilePath, logger);
                if (convertedProject == null)
                {
                    throw new ProjectUpgradeFailedException();
                }

                // OK, we need upgrade, save SCC info and ask if project file can be edited
                if (upgradeRequired != 0)
                {
                    // 2. save SCC related info
                    this.m_lastUpgradedProjectFile = projectFilePath;
                    foreach (var property in convertedProject.Properties)
                    {
                        switch (property.Name)
                        {
                            case SCC_LOCAL_PATH:
                                this.m_sccLocalPath = property.Value;
                                break;
                            case SCC_AUX_PATH:
                                this.m_sccAuxPath = property.Value;
                                break;
                            case SCC_PROVIDER:
                                this.m_sccProvider = property.Value;
                                break;
                            case SCC_PROJECT_NAME:
                                this.m_sccProjectName = property.Value;
                                break;
                            default:
                                break;
                        }
                    }

                    // 3. Query for edit (this call may query information stored on previous step)
                    IVsQueryEditQuerySave2 queryEdit = site.GetService(typeof(SVsQueryEditQuerySave)) as IVsQueryEditQuerySave2;
                    if (queryEdit != null)
                    {
                        uint editVerdict;
                        uint queryEditMoreInfo;
                        const tagVSQueryEditFlags tagVSQueryEditFlags_QEF_AllowUnopenedProjects = (tagVSQueryEditFlags)0x80;

                        int hr = queryEdit.QueryEditFiles(
                            (uint)(tagVSQueryEditFlags.QEF_ForceEdit_NoPrompting | tagVSQueryEditFlags.QEF_DisallowInMemoryEdits | tagVSQueryEditFlags_QEF_AllowUnopenedProjects),
                            1, new[] { projectFilePath }, null, null, out editVerdict, out queryEditMoreInfo);

                        if (ErrorHandler.Failed(hr))
                        {
                            throw new ProjectUpgradeFailedException();
                        }

                        if (editVerdict != (uint)tagVSQueryEditResult.QER_EditOK)
                        {
                            throw new ProjectUpgradeFailedException(SR.GetString(SR.UpgradeCannotOpenProjectFileForEdit));
                        }

                        // If file was modified during the checkout, maybe upgrade is not needed
                        if ((queryEditMoreInfo & (uint)tagVSQueryEditResultFlags.QER_MaybeChanged) != 0)
                        {
                            ((IVsProjectUpgradeViaFactory)this).UpgradeProject_CheckOnly(projectFilePath, upgradeLogger, out upgradeRequired, out newProjectFactory, out ignore);
                            if (upgradeRequired == 0)
                            {
                                if (logger != null)
                                {
                                    logger.LogInfo(SR.GetString(SR.UpgradeNoNeedToUpgradeAfterCheckout));
                                }

                                return VSConstants.S_OK;
                            }
                        }
                    }
                }

                // 3.1 copy backup 
                BackupProjectFilesIfNeeded(projectFilePath, logger, flag, copyLocation, convertedProject);

                // 4. if we have performed upgrade - save project to disk
                if (upgradeRequired != 0)
                {
                    try
                    {
                        convertedProject.Save(projectFilePath);
                    }
                    catch (Exception ex)
                    {
                        throw new ProjectUpgradeFailedException(ex.Message, ex);
                    }
                }
                // 821083: "Converted" should NOT be localized - it is referenced in the XSLT used to display the UpgradeReport
                logger.LogStatus("Converted");

            }
            catch (ProjectUpgradeFailedException ex)
            {
                var exception = ex.InnerException ?? ex;

                if (exception != null && !string.IsNullOrEmpty(exception.Message))
                    logger.LogError(exception.Message);

                upgradeFullyQualifiedFileName = "";
                m_lastUpgradedProjectFile = null;
                return VSConstants.E_FAIL;
            }
            return VSConstants.S_OK;
        }
예제 #10
0
        private void BackupProjectFilesIfNeeded(
            string projectFilePath,
            ProjectUpgradeLogger logger,
            __VSPPROJECTUPGRADEVIAFACTORYFLAGS flag,
            string copyLocation,
            ProjectRootElement convertedProject
            )
        {
            var projectName     = Path.GetFileNameWithoutExtension(projectFilePath);
            var projectFileName = Path.GetFileName(projectFilePath);

            if (HasCopyBackupFlag(flag) || HasSxSBackupFlag(flag))
            {
                if (HasSxSBackupFlag(flag) && !Directory.Exists(copyLocation))
                {
                    Debug.Assert(false, "Env should create the directory for us");
                    throw new ProjectUpgradeFailedException();
                }

                // copy project file
                {
                    var targetFilePath = Path.Combine(copyLocation, projectFileName);
                    if (HasSxSBackupFlag(flag))
                    {
                        bool ignored;
                        targetFilePath = GetUniqueFileName(targetFilePath + ".old", out ignored);
                    }

                    try
                    {
                        File.Copy(projectFilePath, targetFilePath);
                        logger.LogInfo(SR.GetString(SR.ProjectBackupSuccessful, targetFilePath));
                    }
                    catch (Exception ex)
                    {
                        var message = SR.GetString(SR.ErrorMakingProjectBackup, targetFilePath);
                        throw new ProjectUpgradeFailedException(string.Format("{0} : {1}", message, ex.Message));
                    }
                }

                if (HasCopyBackupFlag(flag))
                {
                    //Now iterate through the project items and copy them to the new location
                    //All projects under the solution retain its folder hierarchy
                    var types = new[] { "Compile", "None", "Content", "EmbeddedResource", "Resource", "BaseApplicationManifest", "ApplicationDefinition", "Page" };

                    var metadataLookup =
                        convertedProject
                        .Items
                        .GroupBy(i => i.ItemType)
                        .ToDictionary(x => x.Key);

                    var sourceProjectDir = Path.GetDirectoryName(projectFilePath);
                    foreach (var ty in types)
                    {
                        if (metadataLookup.ContainsKey(ty))
                        {
                            foreach (var item in metadataLookup[ty])
                            {
                                var    linkMetadataElement = item.Metadata.FirstOrDefault(me => me.Name == "Link");
                                string linked = linkMetadataElement != null && !string.IsNullOrEmpty(linkMetadataElement.Value) ? linkMetadataElement.Value : null;

                                var include = item.Include;

                                Debug.Assert(!string.IsNullOrEmpty(include));

                                string sourceFilePath;

                                var targetFileName = Path.Combine(copyLocation, linked ?? include);

                                if (Path.IsPathRooted(include))
                                {
                                    //if the path is fully qualified already, then just use it
                                    sourceFilePath = include;
                                }
                                else
                                {
                                    //otherwise tack the filename on to the path
                                    sourceFilePath = Path.Combine(sourceProjectDir, include);
                                }
                                if (linked != null && include[0] == '.')
                                {
                                    //if linked file up a level (or more), then turn it into a path without the ..\ in the middle
                                    sourceFilePath = Path.GetFullPath(sourceFilePath);
                                }

                                bool initiallyUnique;
                                targetFileName = GetUniqueFileName(targetFileName, out initiallyUnique);
                                if (!initiallyUnique)
                                {
                                    logger.LogInfo(SR.GetString(SR.BackupNameConflict, targetFileName));
                                }

                                //Warn user in upgrade log if linked files are used "project may not build"
                                if (linked != null && HasCopyBackupFlag(flag))
                                {
                                    logger.LogWarning(SR.GetString(SR.ProjectContainsLinkedFile, targetFileName));
                                }

                                // ensure target folder exists
                                Directory.CreateDirectory(Path.GetDirectoryName(targetFileName));

                                try
                                {
                                    File.Copy(sourceFilePath, targetFileName);
                                    logger.LogInfo(SR.GetString(SR.BackupSuccessful, targetFileName));
                                }
                                catch (Exception ex)
                                {
                                    var message = SR.GetString(SR.ErrorMakingBackup, targetFileName);
                                    logger.LogError(string.Format("{0} : {1}", message, ex.Message));
                                }
                            }
                        }
                    }
                }
            }
        }
예제 #11
0
        public virtual int UpgradeProject(
            string projectFilePath,
            uint upgradeFlag,
            string initialCopyLocation,
            out string upgradeFullyQualifiedFileName,
            IVsUpgradeLogger upgradeLogger,
            out int upgradeRequired,
            out Guid newProjectFactory
            )
        {
            // initialize out params in case of failure
            upgradeFullyQualifiedFileName = null;
            upgradeRequired   = 0;
            newProjectFactory = Guid.Empty;

            __VSPPROJECTUPGRADEVIAFACTORYFLAGS flag;
            string copyLocation = initialCopyLocation;
            var    r            = NormalizeUpgradeFlag(upgradeFlag, out flag, ref copyLocation);

            if (r != VSConstants.S_OK)
            {
                return(r);
            }

            string projectName = Path.GetFileNameWithoutExtension(projectFilePath);
            var    logger      = new ProjectUpgradeLogger(upgradeLogger, projectName, projectFilePath);

            uint ignore;

            ((IVsProjectUpgradeViaFactory)this).UpgradeProject_CheckOnly(projectFilePath, upgradeLogger, out upgradeRequired, out newProjectFactory, out ignore);

            // no upgrade required and not 'copy-backup'
            if (upgradeRequired == 0 && !HasCopyBackupFlag(flag))
            {
                //Write an informational message "No upgrade required for project foo"?
                logger.LogInfo(SR.GetString(SR.ProjectConversionNotRequired));
                logger.LogInfo(SR.GetString(SR.ConversionNotRequired));

                upgradeFullyQualifiedFileName = projectFilePath;
                return(VSConstants.S_OK);
            }

            // upgrade is not required but backup may still be needed

            var projectFileName = Path.GetFileName(projectFilePath);

            upgradeFullyQualifiedFileName = projectFilePath;

            if (HasSxSBackupFlag(flag))
            {
                // for SxS call use location near the original file
                copyLocation = Path.GetDirectoryName(projectFilePath);
            }

            // workflow is taken from vsprjfactory.cpp (vsproject\vsproject)
            // 1. convert the project (in-memory)
            // 2. save SCC related info
            // 3. use data stored on step 2 in GetSccInfo calls (during QueryEditFiles)
            // 4. if succeeded - save project on disk
            // F# doesn't use .user file so all related code is skipped
            try
            {
                // load MSBuild project in memory: this will be needed in all cases not depending whether upgrade is required or not
                // we use this project to determine the set of files to copy
                ProjectRootElement convertedProject = ConvertProject(projectFilePath, logger);
                if (convertedProject == null)
                {
                    throw new ProjectUpgradeFailedException();
                }

                // OK, we need upgrade, save SCC info and ask if project file can be edited
                if (upgradeRequired != 0)
                {
                    // 2. save SCC related info
                    this.m_lastUpgradedProjectFile = projectFilePath;
                    foreach (var property in convertedProject.Properties)
                    {
                        switch (property.Name)
                        {
                        case SCC_LOCAL_PATH:
                            this.m_sccLocalPath = property.Value;
                            break;

                        case SCC_AUX_PATH:
                            this.m_sccAuxPath = property.Value;
                            break;

                        case SCC_PROVIDER:
                            this.m_sccProvider = property.Value;
                            break;

                        case SCC_PROJECT_NAME:
                            this.m_sccProjectName = property.Value;
                            break;

                        default:
                            break;
                        }
                    }

                    // 3. Query for edit (this call may query information stored on previous step)
                    IVsQueryEditQuerySave2 queryEdit = site.GetService(typeof(SVsQueryEditQuerySave)) as IVsQueryEditQuerySave2;
                    if (queryEdit != null)
                    {
                        uint editVerdict;
                        uint queryEditMoreInfo;
                        const tagVSQueryEditFlags tagVSQueryEditFlags_QEF_AllowUnopenedProjects = (tagVSQueryEditFlags)0x80;

                        int hr = queryEdit.QueryEditFiles(
                            (uint)(tagVSQueryEditFlags.QEF_ForceEdit_NoPrompting | tagVSQueryEditFlags.QEF_DisallowInMemoryEdits | tagVSQueryEditFlags_QEF_AllowUnopenedProjects),
                            1, new[] { projectFilePath }, null, null, out editVerdict, out queryEditMoreInfo);

                        if (ErrorHandler.Failed(hr))
                        {
                            throw new ProjectUpgradeFailedException();
                        }

                        if (editVerdict != (uint)tagVSQueryEditResult.QER_EditOK)
                        {
                            throw new ProjectUpgradeFailedException(SR.GetString(SR.UpgradeCannotOpenProjectFileForEdit));
                        }

                        // If file was modified during the checkout, maybe upgrade is not needed
                        if ((queryEditMoreInfo & (uint)tagVSQueryEditResultFlags.QER_MaybeChanged) != 0)
                        {
                            ((IVsProjectUpgradeViaFactory)this).UpgradeProject_CheckOnly(projectFilePath, upgradeLogger, out upgradeRequired, out newProjectFactory, out ignore);
                            if (upgradeRequired == 0)
                            {
                                if (logger != null)
                                {
                                    logger.LogInfo(SR.GetString(SR.UpgradeNoNeedToUpgradeAfterCheckout));
                                }

                                return(VSConstants.S_OK);
                            }
                        }
                    }
                }

                // 3.1 copy backup
                BackupProjectFilesIfNeeded(projectFilePath, logger, flag, copyLocation, convertedProject);

                // 4. if we have performed upgrade - save project to disk
                if (upgradeRequired != 0)
                {
                    try
                    {
                        convertedProject.Save(projectFilePath);
                    }
                    catch (Exception ex)
                    {
                        throw new ProjectUpgradeFailedException(ex.Message, ex);
                    }
                }
                // 821083: "Converted" should NOT be localized - it is referenced in the XSLT used to display the UpgradeReport
                logger.LogStatus("Converted");
            }
            catch (ProjectUpgradeFailedException ex)
            {
                var exception = ex.InnerException ?? ex;

                if (exception != null && !string.IsNullOrEmpty(exception.Message))
                {
                    logger.LogError(exception.Message);
                }

                upgradeFullyQualifiedFileName = "";
                m_lastUpgradedProjectFile     = null;
                return(VSConstants.E_FAIL);
            }
            return(VSConstants.S_OK);
        }