Esempio n. 1
0
        /// <summary>
        /// Registers the supported platforms.
        /// </summary>
        /// <param name="platforms">The platforms.</param>
        /// <exception cref="System.ArgumentNullException">platforms</exception>
        public static void RegisterSupportedPlatforms(List <SolutionPlatform> platforms)
        {
            if (platforms == null)
            {
                throw new ArgumentNullException("platforms");
            }
            if (supportedPlatforms.Count > 0)
            {
                throw new InvalidOperationException("Cannot register new platforms. RegisterSupportedPlatforms can only be called once");
            }

            supportedPlatforms.AddRange(platforms);
        }
        public static void SaveSolution(PackageSession session, ILogger log)
        {
            // If the solution path is not set, we can't save a solution (sln)
            if (session.SolutionPath == null)
            {
                return;
            }

            var solutionPath = UPath.Combine(Environment.CurrentDirectory, session.SolutionPath);

            try
            {
                Solution solution;

                var solutionDir = solutionPath.GetParent();

                // If the solution already exists, we need to update it
                if (File.Exists(solutionPath))
                {
                    solution = Solution.FromFile(solutionPath);
                }
                else
                {
                    solution = new Solution {
                        FullPath = solutionPath
                    };
                    solution.Headers.Add(SolutionHeader);
                }

                // Pre-create solution wide global sections
                if (!solution.GlobalSections.Contains("SolutionConfigurationPlatforms"))
                {
                    solution.GlobalSections.Add(new Section("SolutionConfigurationPlatforms", "GlobalSection", "preSolution", Enumerable.Empty <PropertyItem>()));
                }
                if (!solution.GlobalSections.Contains("ProjectConfigurationPlatforms"))
                {
                    solution.GlobalSections.Add(new Section("ProjectConfigurationPlatforms", "GlobalSection", "postSolution", Enumerable.Empty <PropertyItem>()));
                }
                if (!solution.GlobalSections.Contains("NestedProjects"))
                {
                    solution.GlobalSections.Add(new Section("NestedProjects", "GlobalSection", "preSolution", Enumerable.Empty <PropertyItem>()));
                }

                // ---------------------------------------------
                // 0. Pre-select only platforms effectively used by this session
                // ---------------------------------------------
                var platformsUsedBySession = new SolutionPlatformCollection();
                platformsUsedBySession.AddRange(AssetRegistry.SupportedPlatforms.Where(platform => platform.Type == PlatformType.Windows));

                foreach (var package in session.LocalPackages)
                {
                    foreach (var profile in package.Profiles.Where(profile => profile.Platform != PlatformType.Shared && profile.ProjectReferences.Count > 0))
                    {
                        var platformType = profile.Platform;
                        if (!platformsUsedBySession.Contains(platformType))
                        {
                            platformsUsedBySession.AddRange(AssetRegistry.SupportedPlatforms.Where(platform => platform.Type == platformType));
                        }
                    }
                }

                // ---------------------------------------------
                // 1. Update configuration/platform
                // ---------------------------------------------
                var configs = new List <Tuple <string, SolutionPlatform, SolutionPlatformPart> >();
                foreach (var configName in platformsUsedBySession.SelectMany(solutionPlatform => solutionPlatform.Configurations).Select(config => config.Name).Distinct())
                {
                    foreach (var platform in platformsUsedBySession)
                    {
                        foreach (var platformPart in platform.GetParts())
                        {
                            // Skip platforms with IncludeInSolution == false
                            if (!platformPart.IncludeInSolution)
                            {
                                continue;
                            }

                            configs.Add(new Tuple <string, SolutionPlatform, SolutionPlatformPart>(configName, platform, platformPart));
                        }
                    }
                }

                // Order per config and then per platform names
                configs = configs.OrderBy(part => part.Item1, StringComparer.InvariantCultureIgnoreCase).ThenBy(part => part.Item3.SafeSolutionName, StringComparer.InvariantCultureIgnoreCase).ToList();

                // Write configs in alphabetical order to avoid changes in sln after it is generated
                var solutionPlatforms = solution.GlobalSections["SolutionConfigurationPlatforms"];
                solutionPlatforms.Properties.Clear();
                foreach (var config in configs)
                {
                    var solutionConfigPlatform = string.Format("{0}|{1}", config.Item1, config.Item3.SafeSolutionName);
                    if (!solutionPlatforms.Properties.Contains(solutionConfigPlatform))
                    {
                        solutionPlatforms.Properties.Add(new PropertyItem(solutionConfigPlatform, solutionConfigPlatform));
                    }
                }

                // Remove projects that are no longer available on the disk
                var projectToRemove = solution.Projects.Where(project => !project.IsSolutionFolder && !File.Exists(project.FullPath)).ToList();
                foreach (var project in projectToRemove)
                {
                    solution.Projects.Remove(project);
                }

                // ---------------------------------------------
                // 2. Update each package
                // ---------------------------------------------
                foreach (var package in session.LocalPackages)
                {
                    if (string.IsNullOrWhiteSpace(package.Meta.Name))
                    {
                        log.Error($"Error while saving solution [{solutionPath}]. Package [{package.FullPath}] should have a Meta.Name");
                        continue;
                    }

                    var packageFolder = solution.Projects.FindByGuid((Guid)package.Id);

                    // Packages are created as solution folders in VisualStudio
                    if (packageFolder == null)
                    {
                        // Create this package as a Solution Folder
                        packageFolder = new Project(solution,
                                                    (Guid)package.Id,
                                                    KnownProjectTypeGuid.SolutionFolder,
                                                    package.Meta.Name,
                                                    package.Meta.Name,
                                                    Guid.Empty,
                                                    Enumerable.Empty <Section>(),
                                                    Enumerable.Empty <PropertyItem>(),
                                                    Enumerable.Empty <PropertyItem>());

                        // As it is making a copy, we need to get it back
                        solution.Projects.Add(packageFolder);
                        packageFolder = solution.Projects[package.Id];
                    }

                    // Update the path to the solution everytime we save a package
                    packageFolder.Sections.Clear();
                    var relativeUrl = package.FullPath.MakeRelative(solutionDir);
                    packageFolder.Sections.Add(new Section(SiliconStudioPackage, "ProjectSection", "preProject", new[] { new PropertyItem(relativeUrl, relativeUrl) }));

                    // ---------------------------------------------
                    // 2.1. Update each project
                    // ---------------------------------------------
                    foreach (var profile in package.Profiles.OrderBy(x => x.Platform == PlatformType.Windows ? 0 : 1))
                    {
                        foreach (var project in profile.ProjectReferences)
                        {
                            var projectInSolution = solution.Projects.FindByGuid(project.Id);

                            if (projectInSolution == null)
                            {
                                var projectRelativePath = project.Location.MakeRelative(solutionDir);

                                // Create this package as a Solution Folder
                                projectInSolution = new Project(solution,
                                                                project.Id,
                                                                KnownProjectTypeGuid.CSharp,
                                                                project.Location.GetFileNameWithoutExtension(),
                                                                projectRelativePath.ToWindowsPath(),
                                                                package.Id,
                                                                Enumerable.Empty <Section>(),
                                                                Enumerable.Empty <PropertyItem>(),
                                                                Enumerable.Empty <PropertyItem>());

                                solution.Projects.Add(projectInSolution);

                                // Resolve it again, as the original code is making a clone of it (why?)
                                projectInSolution = solution.Projects.FindByGuid(project.Id);
                            }

                            // Projects are always in a package (solution folder) in the solution
                            projectInSolution.ParentGuid = package.Id;

                            // Update platforms per project (active solution and build flag per platform)

                            // Clear all platform properties for this project and recompute them here
                            projectInSolution.PlatformProperties.Clear();

                            foreach (var config in configs)
                            {
                                var configName   = config.Item1;
                                var platform     = config.Item2;
                                var platformPart = config.Item3;

                                // Filter exe project types
                                if (project.Type == ProjectType.Executable && !platformPart.UseWithExecutables)
                                {
                                    continue;
                                }

                                var platformName = platformPart.SafeSolutionName;

                                var solutionConfigPlatform = string.Format("{0}|{1}", configName, platformName);

                                var configNameInProject   = configName;
                                var platformNameInProject = platformPart.GetProjectName(project.Type);

                                var platformTarget = platform;
                                if (profile.Platform != PlatformType.Shared)
                                {
                                    platformTarget = platformsUsedBySession.FirstOrDefault(plat => plat.Type == profile.Platform);
                                    if (platformTarget == null)
                                    {
                                        // This should not happen as we control our platforms, but when we develop a new one
                                        // we might get it and it is better to cleary state why we are failing.
                                        log.Error("Project contains an unsupported platform " + profile.Platform);
                                        throw new InvalidOperationException("Unsupported platform " + profile.Platform);
                                    }
                                }

                                bool isPartOfBuild = platformTarget == platform;
                                // If the config doesn't exist for this platform, just use the default config name
                                if (!platformTarget.Configurations.Contains(configName))
                                {
                                    configNameInProject = platformTarget.Configurations.FirstOrDefault().Name;
                                    isPartOfBuild       = false;
                                }

                                // If the config doesn't exist for this platform, just use the default config name
                                if (platformTarget.GetParts().All(part => part.GetProjectName(project.Type) != platformNameInProject))
                                {
                                    platformNameInProject = platformTarget.GetParts().FirstOrDefault(part => part.IsProjectHandled(project.Type)).SafeSolutionName;
                                    isPartOfBuild         = false;
                                }

                                var projectConfigPlatform = string.Format("{0}|{1}", configNameInProject, platformNameInProject);

                                var propertyActive = solutionConfigPlatform + ".ActiveCfg";
                                var propertyBuild  = solutionConfigPlatform + ".Build.0";

                                if (!projectInSolution.PlatformProperties.Contains(propertyActive))
                                {
                                    projectInSolution.PlatformProperties.Remove(propertyActive);
                                    projectInSolution.PlatformProperties.Add(new PropertyItem(propertyActive, projectConfigPlatform));
                                }

                                // Only add Build and Deploy for supported configs
                                if (isPartOfBuild)
                                {
                                    projectInSolution.PlatformProperties.Remove(propertyBuild);
                                    projectInSolution.PlatformProperties.Add(new PropertyItem(propertyBuild, projectConfigPlatform));

                                    // If the project is an executable, mark it as deploy
                                    if (project.Type == ProjectType.Executable)
                                    {
                                        var propertyDeploy = solutionConfigPlatform + ".Deploy.0";
                                        projectInSolution.PlatformProperties.Remove(propertyDeploy);
                                        projectInSolution.PlatformProperties.Add(new PropertyItem(propertyDeploy, projectConfigPlatform));
                                    }
                                }
                            }
                        }
                    }

                    // ---------------------------------------------
                    // 3. Remove unused packages from the solution
                    // ---------------------------------------------
                    for (int i = solution.Projects.Count - 1; i >= 0; i--)
                    {
                        var project = solution.Projects[i];
                        if (IsPackage(project) && !session.Packages.ContainsById(project.Guid))
                        {
                            solution.Projects.RemoveAt(i);
                        }
                    }
                }

                solution.Save();
            }
            catch (Exception ex)
            {
                log.Error($"Error while saving solution [{solutionPath}]", ex);
            }
        }