private void BackupProjectFilesIfNeeded()

in vsintegration/src/FSharp.ProjectSystem.Base/Project/ProjectFactory.cs [580:697]


        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));
                                }                                
                            }
                        }
                    }
                }
            }
        }