private void GenerateTopLevelDependenciesProject(UnityProjectInfo unityProjectInfo)
        {
            string projectPath = GetProjectFilePath(Utilities.AssetPath, "Dependencies");
            string propsPath   = GetProjectFilePath(generatedOutputFolder.FullName, "Dependencies").Replace(".csproj", ".g.props");
            string targetsPath = GetProjectFilePath(generatedOutputFolder.FullName, "Dependencies").Replace(".csproj", ".g.targets");

            ITemplatePart propsFileTemplate        = dependenciesPropsTemplate.Root;
            ITemplatePart projectReferenceTemplate = propsFileTemplate.Templates["PROJECT_REFERENCE"];

            TemplateReplacementSet replacementSet = propsFileTemplate.CreateReplacementSet();

            // We use this to emulate the platform support for all
            Dictionary <BuildTarget, CompilationPlatformInfo> allPlatforms = unityProjectInfo.AvailablePlatforms.ToDictionary(t => t.BuildTarget, t => t);

            foreach (CSProjectInfo projectInfo in unityProjectInfo.CSProjects.Values)
            {
                List <string> platformConditions = GetPlatformConditions(allPlatforms, projectInfo.InEditorPlatforms.Keys);
                ProcessProjectDependency(replacementSet, projectReferenceTemplate, projectInfo, platformConditions);
            }

            dependenciesPropsTemplate.Write(propsPath, replacementSet);

            ITemplatePart targetsFileTemplate = dependenciesTargetsTemplate.Root;

            dependenciesTargetsTemplate.Write(targetsPath, propsFileTemplate.CreateReplacementSet());

            if (!File.Exists(projectPath))
            {
                dependenciesProjectTemplate.Write(projectPath, dependenciesProjectTemplate.Root.CreateReplacementSet());
            }
        }
        ///<inherit-doc/>
        public void ExportProject(UnityProjectInfo unityProjectInfo, CSProjectInfo projectInfo)
        {
            string projectPath = GetProjectPath(projectInfo).FullName;

            bool generatedProject;

            switch (projectInfo.AssemblyDefinitionInfo.AssetLocation)
            {
            case AssetLocation.BuiltInPackage:
            case AssetLocation.External:
            case AssetLocation.PackageLibraryCache:
                generatedProject = true;
                break;

            case AssetLocation.Project:
            case AssetLocation.Package:
                generatedProject = false;
                break;

            default:
                throw new InvalidOperationException("The project's assembly definition file is in an unknown location.");
            }

            if (!TryExportPropsFile(unityProjectInfo, projectInfo))
            {
                Debug.LogError($"Error exporting the generated props file for {projectInfo.Name}");
                return;
            }

            if (!TryExportTargetsFile(unityProjectInfo, projectInfo))
            {
                Debug.LogError($"Error exporting the generated targets file for {projectInfo.Name}");
                return;
            }

            if (generatedProject)
            {
                generatedProjectFileTemplate.Write(projectPath, generatedProjectFileTemplate.Root.CreateReplacementSet());
                File.SetAttributes(projectPath, FileAttributes.ReadOnly);
            }
            else if (!File.Exists(projectPath))
            {
                projectFileTemplate.Write(projectPath, projectFileTemplate.Root.CreateReplacementSet());
            }
        }
        private bool TryExportTargetsFile(UnityProjectInfo unityProjectInfo, CSProjectInfo projectInfo)
        {
            string projectPath = GetProjectFilePath(generatedOutputFolder, projectInfo);

            ITemplatePart          rootTemplatePart               = targetsFileTemplate.Root;
            TemplateReplacementSet rootReplacementSet             = rootTemplatePart.CreateReplacementSet();
            ITemplatePart          supportedPlatformBuildTemplate = rootTemplatePart.Templates["SUPPORTED_PLATFORM_BUILD_CONDITION"];

            PopulateSupportedPlatformBuildConditions(supportedPlatformBuildTemplate, rootReplacementSet, "InEditor", projectInfo.InEditorPlatforms);
            PopulateSupportedPlatformBuildConditions(supportedPlatformBuildTemplate, rootReplacementSet, "Player", projectInfo.PlayerPlatforms);

            string targetsFilePath = projectPath.Replace("csproj", "g.targets");

            targetsFileTemplate.Write(targetsFilePath, rootReplacementSet);
            File.SetAttributes(targetsFilePath, FileAttributes.ReadOnly);

            return(true);
        }
        public void GenerateDirectoryPropsFile(UnityProjectInfo unityProjectInfo)
        {
            string outputPath = Path.Combine(Utilities.ProjectPath, "MSBuildForUnity.Common.props");

            ITemplatePart          rootTemplate       = msbuildForUnityCommonTemplate.Root;
            TemplateReplacementSet rootReplacementSet = rootTemplate.CreateReplacementSet(null);

            rootTemplate.Tokens["GENERATED_OUTPUT_DIRECTORY"].AssignValue(rootReplacementSet, generatedOutputFolder.FullName);
            rootTemplate.Tokens["UNITY_PROJECT_ASSETS_PATH"].AssignValue(rootReplacementSet, Path.GetFullPath(Application.dataPath));

            rootTemplate.Tokens["CURRENT_UNITY_PLATFORM"].AssignValue(rootReplacementSet, unityProjectInfo.CurrentPlayerPlatform.Name);
            rootTemplate.Tokens["CURRENT_TARGET_FRAMEWORK"].AssignValue(rootReplacementSet, unityProjectInfo.CurrentPlayerPlatform.TargetFramework.AsMSBuildString());

            string[] versionParts = Application.unityVersion.Split('.');
            rootTemplate.Tokens["UNITY_MAJOR_VERSION"].AssignValue(rootReplacementSet, versionParts[0]);
            rootTemplate.Tokens["UNITY_MINOR_VERSION"].AssignValue(rootReplacementSet, versionParts[1]);

            msbuildForUnityCommonTemplate.Write(outputPath, rootReplacementSet);
        }
        private bool TryExportPropsFile(UnityProjectInfo unityProjectInfo, CSProjectInfo projectInfo)
        {
            ITemplatePart          rootTemplatePart   = propsFileTemplate.Root;
            TemplateReplacementSet rootReplacementSet = rootTemplatePart.CreateReplacementSet();

            ITemplatePart projectReferenceSetTemplatePart = rootTemplatePart.Templates["PROJECT_REFERENCE_SET"];
            ITemplatePart sourceExcludeTemplatePart       = rootTemplatePart.Templates["SOURCE_EXCLUDE"];

            string projectPath = GetProjectFilePath(generatedOutputFolder, projectInfo);

            foreach (AssemblyDefinitionInfo nestedAsmdef in projectInfo.AssemblyDefinitionInfo.NestedAssemblyDefinitionFiles)
            {
                TemplateReplacementSet replacementSet = sourceExcludeTemplatePart.CreateReplacementSet(rootReplacementSet);
                sourceExcludeTemplatePart.Tokens["EXCLUDE_DIRECTORY_PATH"].AssignValue(replacementSet, nestedAsmdef.Directory.FullName);
            }

            HashSet <string> inEditorSearchPaths = new HashSet <string>(), playerSearchPaths = new HashSet <string>();

            CreateProjectReferencesSet(projectInfo, projectReferenceSetTemplatePart, rootReplacementSet, inEditorSearchPaths, true);
            CreateProjectReferencesSet(projectInfo, projectReferenceSetTemplatePart, rootReplacementSet, playerSearchPaths, false);

            rootTemplatePart.Tokens["PROJECT_GUID"].AssignValue(rootReplacementSet, projectInfo.Guid.ToString());
            rootTemplatePart.Tokens["ALLOW_UNSAFE"].AssignValue(rootReplacementSet, projectInfo.AssemblyDefinitionInfo.allowUnsafeCode.ToString());
            rootTemplatePart.Tokens["LANGUAGE_VERSION"].AssignValue(rootReplacementSet, MSBuildTools.CSharpVersion);
            rootTemplatePart.Tokens["DEVELOPMENT_BUILD"].AssignValue(rootReplacementSet, "false");
            rootTemplatePart.Tokens["IS_EDITOR_ONLY_TARGET"].AssignValue(rootReplacementSet, (projectInfo.ProjectType == ProjectType.EditorAsmDef || projectInfo.ProjectType == ProjectType.PredefinedEditorAssembly).ToString());
            rootTemplatePart.Tokens["UNITY_EDITOR_INSTALL_FOLDER"].AssignValue(rootReplacementSet, Path.GetDirectoryName(EditorApplication.applicationPath) + "\\");
            rootTemplatePart.Tokens["PROJECT_NAME"].AssignValue(rootReplacementSet, projectInfo.Name);
            rootTemplatePart.Tokens["DEFAULT_PLATFORM"].AssignValue(rootReplacementSet, unityProjectInfo.AvailablePlatforms.First(t => t.BuildTarget == BuildTarget.StandaloneWindows).Name);
            rootTemplatePart.Tokens["SUPPORTED_PLATFORMS"].AssignValue(rootReplacementSet, new DelimitedStringSet(";", unityProjectInfo.AvailablePlatforms.Select(t => t.Name)));
            rootTemplatePart.Tokens["INEDITOR_ASSEMBLY_SEARCH_PATHS"].AssignValue(rootReplacementSet, new DelimitedStringSet(";", inEditorSearchPaths));
            rootTemplatePart.Tokens["PLAYER_ASSEMBLY_SEARCH_PATHS"].AssignValue(rootReplacementSet, new DelimitedStringSet(";", playerSearchPaths));
            rootTemplatePart.Tokens["PLATFORM_PROPS_FOLDER_PATH"].AssignValue(rootReplacementSet, generatedOutputFolder.FullName);
            rootTemplatePart.Tokens["PROJECT_DIRECTORY_PATH"].AssignValue(rootReplacementSet, projectInfo.AssemblyDefinitionInfo.Directory.FullName);

            string propsFilePath = projectPath.Replace("csproj", "g.props");

            propsFileTemplate.Write(propsFilePath, rootReplacementSet);
            File.SetAttributes(propsFilePath, FileAttributes.ReadOnly);
            return(true);
        }
 public string GetSolutionFilePath(UnityProjectInfo unityProjectInfo)
 {
     return(Path.Combine(Utilities.AssetPath, $"{unityProjectInfo.UnityProjectName}.{MSBuildFileSuffix}.sln"));
 }
        ///<inherit-doc/>
        public void ExportSolution(UnityProjectInfo unityProjectInfo)
        {
            string solutionFilePath = GetSolutionFilePath(unityProjectInfo);

            if (File.Exists(solutionFilePath))
            {
                File.Delete(solutionFilePath);
            }
            ITemplatePart          rootTemplatePart   = solutionFileTemplate.Root;
            TemplateReplacementSet rootReplacementSet = rootTemplatePart.CreateReplacementSet();

            ITemplatePart projectTemplate               = rootTemplatePart.Templates["PROJECT"];
            ITemplatePart folderTemplate                = rootTemplatePart.Templates["FOLDER"];
            ITemplatePart configPlatformTemplate        = rootTemplatePart.Templates["CONFIGURATION_PLATFORM"];
            ITemplatePart configPlatformMappingTemplate = rootTemplatePart.Templates["CONFIGURATION_PLATFORM_MAPPING"];
            ITemplatePart configPlatformEnabledTemplate = rootTemplatePart.Templates["CONFIGURATION_PLATFORM_ENABLED"];
            ITemplatePart folderNestedProjectsTemplate  = rootTemplatePart.Templates["FOLDER_NESTED_PROJECTS"];

            CSProjectInfo[]      unorderedProjects = unityProjectInfo.CSProjects.Select(t => t.Value).ToArray();
            List <CSProjectInfo> orderedProjects   = new List <CSProjectInfo>();

            while (orderedProjects.Count < unorderedProjects.Length)
            {
                bool oneRemoved = false;
                for (int i = 0; i < unorderedProjects.Length; i++)
                {
                    if (unorderedProjects[i] == null)
                    {
                        continue;
                    }

                    if (unorderedProjects[i].ProjectDependencies.Count == 0 || unorderedProjects[i].ProjectDependencies.All(t => orderedProjects.Contains(t.Dependency)))
                    {
                        orderedProjects.Add(unorderedProjects[i]);

                        unorderedProjects[i] = null;
                        oneRemoved           = true;
                    }
                }

                if (!oneRemoved)
                {
                    Debug.LogError($"Possible circular dependency.");
                    break;
                }
            }

            List <CSProjectInfo> builtinPackages  = new List <CSProjectInfo>();
            List <CSProjectInfo> importedPacakges = new List <CSProjectInfo>();
            List <CSProjectInfo> externalPackages = new List <CSProjectInfo>();

            foreach (CSProjectInfo project in orderedProjects)
            {
                TemplateReplacementSet replacementSet = projectTemplate.CreateReplacementSet(rootReplacementSet);
                ProcessProjectEntry(project.Name, GetProjectPath(project).FullName, project.Guid, project.ProjectDependencies, projectTemplate, replacementSet);

                switch (project.AssemblyDefinitionInfo.AssetLocation)
                {
                case AssetLocation.BuiltInPackage:
                    builtinPackages.Add(project);
                    break;

                case AssetLocation.PackageLibraryCache:
                    importedPacakges.Add(project);
                    break;

                case AssetLocation.External:
                    externalPackages.Add(project);
                    break;

                default: break;
                }
            }

            // Add the "Dependencies" project
            ProcessProjectEntry("Dependencies", GetProjectFilePath(Utilities.AssetPath, "Dependencies"), Guid.NewGuid(), null, projectTemplate, projectTemplate.CreateReplacementSet(rootReplacementSet));

            PopulateFolder(folderTemplate, folderNestedProjectsTemplate, rootReplacementSet, "Built In Packages", builtinPackages);
            PopulateFolder(folderTemplate, folderNestedProjectsTemplate, rootReplacementSet, "Imported Packages", importedPacakges);
            PopulateFolder(folderTemplate, folderNestedProjectsTemplate, rootReplacementSet, "External Packages", externalPackages);

            ITemplateToken configPlatform_ConfigurationToken = configPlatformTemplate.Tokens["CONFIGURATION"];
            ITemplateToken configPlatform_PlatformToken      = configPlatformTemplate.Tokens["PLATFORM"];

            foreach (CompilationPlatformInfo platform in unityProjectInfo.AvailablePlatforms)
            {
                TemplateReplacementSet replacementSet = configPlatformTemplate.CreateReplacementSet(rootReplacementSet);
                configPlatform_ConfigurationToken.AssignValue(replacementSet, "InEditor");
                configPlatform_PlatformToken.AssignValue(replacementSet, platform.Name);

                replacementSet = configPlatformTemplate.CreateReplacementSet(rootReplacementSet);
                configPlatform_ConfigurationToken.AssignValue(replacementSet, "Player");
                configPlatform_PlatformToken.AssignValue(replacementSet, platform.Name);
            }

            List <string> disabled = new List <string>();

            foreach (CSProjectInfo project in orderedProjects.Select(t => t))
            {
                void ConfigurationTemplateReplace(ITemplatePart templatePart, TemplateReplacementSet replacementSet, string guid, string configuration, string platform)
                {
                    templatePart.Tokens["PROJECT_GUID"].AssignValue(replacementSet, guid.ToString().ToUpper());
                    templatePart.Tokens["PROJECT_CONFIGURATION"].AssignValue(replacementSet, configuration);
                    templatePart.Tokens["PROJECT_PLATFORM"].AssignValue(replacementSet, platform);
                    templatePart.Tokens["SOLUTION_CONFIGURATION"].AssignValue(replacementSet, configuration);
                    templatePart.Tokens["SOLUTION_PLATFORM"].AssignValue(replacementSet, platform);
                }

                void ProcessMappings(Guid guid, string configuration, IReadOnlyDictionary <BuildTarget, CompilationPlatformInfo> platforms)
                {
                    foreach (CompilationPlatformInfo platform in unityProjectInfo.AvailablePlatforms)
                    {
                        TemplateReplacementSet replacemetSet = configPlatformMappingTemplate.CreateReplacementSet(rootReplacementSet);
                        ConfigurationTemplateReplace(configPlatformMappingTemplate, replacemetSet, guid.ToString(), configuration, platform.Name);

                        if (platforms.ContainsKey(platform.BuildTarget))
                        {
                            replacemetSet = configPlatformEnabledTemplate.CreateReplacementSet(rootReplacementSet);
                            ConfigurationTemplateReplace(configPlatformEnabledTemplate, replacemetSet, guid.ToString(), configuration, platform.Name);
                        }
                    }
                }

                ProcessMappings(project.Guid, "InEditor", project.InEditorPlatforms);
                ProcessMappings(project.Guid, "Player", project.PlayerPlatforms);
            }

            foreach (CSProjectInfo project in unityProjectInfo.CSProjects.Values)
            {
                ExportProject(unityProjectInfo, project);
            }

            GenerateTopLevelDependenciesProject(unityProjectInfo);

            solutionFileTemplate.Write(solutionFilePath, rootReplacementSet);
        }