Beispiel #1
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;
        }
Beispiel #5
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));
                                }
                            }
                        }
                    }
                }
            }
        }
Beispiel #6
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);
        }