Exemple #1
0
        private void ProcessSortedAsmDef(AssemblyDefinitionInfo[] set, ref int currentIndex, Func <Uri, bool> childOfParentFunc, Action <AssemblyDefinitionInfo> addAsChild)
        {
            Uri GetUri(DirectoryInfo d) => d.FullName.EndsWith("\\") ? new Uri(d.FullName) : new Uri(d.FullName + "\\");

            for (; currentIndex < set.Length;)
            {
                AssemblyDefinitionInfo current = set[currentIndex];
                addAsChild(current);

                if (currentIndex + 1 == set.Length)
                {
                    return;
                }

                currentIndex++;

                AssemblyDefinitionInfo next = set[currentIndex];

                Uri potentialBase  = GetUri(current.Directory);
                Uri potentialChild = GetUri(next.Directory);
                if (!childOfParentFunc(potentialChild))
                {
                    return;
                }
                else if (potentialBase.IsBaseOf(potentialChild))
                {
                    ProcessSortedAsmDef(set, ref currentIndex, potentialBase.IsBaseOf, (a) => current.NestedAssemblyDefinitionFiles.Add(a));
                    if (!childOfParentFunc(potentialChild))
                    {
                        return;
                    }
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Parses an asmdef file creating a new instance of <see cref="AssemblyDefinitionInfo"/>.
        /// </summary>
        /// <param name="file">The file representing asmdef.</param>
        /// <param name="unityProjectInfo">Instance of <see cref="UnityProjectInfo"/>,</param>
        /// <param name="assembly">The Unity assembly reference.</param>
        /// <param name="isBuiltInPackage">True whether this asmdef lives in the editor installation folder.</param>
        /// <returns></returns>
        public static AssemblyDefinitionInfo Parse(FileInfo file, UnityProjectInfo unityProjectInfo, Assembly assembly, bool isBuiltInPackage = false)
        {
            if (file.Extension != ".asmdef")
            {
                throw new ArgumentException($"Given file '{file.FullName}' is not an assembly definition file.");
            }
            else if (!file.Exists)
            {
                throw new ArgumentException($"Given file '{file.FullName}' does not exist.");
            }


            AssemblyDefinitionInfo toReturn = JsonUtility.FromJson <AssemblyDefinitionInfo>(File.ReadAllText(file.FullName));

            if (!Utilities.TryGetGuidForAsset(file, out Guid guid))
            {
                Debug.LogError($"Failed to parse AsmDef meta for asm def: '{file.FullName}', didn't find guid.");
            }

            toReturn.assembly       = assembly;
            toReturn.Directory      = file.Directory;
            toReturn.AssetLocation  = Utilities.GetAssetLocation(file);
            toReturn.file           = file;
            toReturn.Guid           = guid;
            toReturn.BuiltInPackage = isBuiltInPackage;
            toReturn.Validate(unityProjectInfo.AvailablePlatforms);
            toReturn.PrecompiledAssemblyReferences = new HashSet <string>(toReturn.precompiledReferences?.Select(t => t.Replace(".dll", string.Empty)) ?? Array.Empty <string>());
            return(toReturn);
        }
        /// <summary>
        /// Exports the project given a template.
        /// </summary>
        /// <param name="projectFileTemplateText">The template of the csproj file.</param>
        /// <param name="projectFilesPath">The output folder where all the props were added.</param>
        internal void ExportProject(string projectFileTemplateText, string projectFilesPath)
        {
            if (File.Exists(ReferencePath.AbsolutePath))
            {
                File.Delete(ReferencePath.AbsolutePath);
            }

            if (Utilities.TryGetXMLTemplate(projectFileTemplateText, "PROJECT_REFERENCE_SET", out string projectReferenceSetTemplate) &&
                Utilities.TryGetXMLTemplate(projectFileTemplateText, "SOURCE_INCLUDE", out string sourceIncludeTemplate) &&
                Utilities.TryGetXMLTemplate(projectFileTemplateText, "SUPPORTED_PLATFORM_BUILD_CONDITION", out string suportedPlatformBuildConditionTemplate))
            {
                List <string>             sourceIncludes        = new List <string>();
                Dictionary <Guid, string> sourceGuidToClassName = new Dictionary <Guid, string>();
                foreach (SourceFileInfo source in AssemblyDefinitionInfo.GetSources())
                {
                    ProcessSourceFile(source, sourceIncludeTemplate, sourceIncludes, sourceGuidToClassName);
                }

                File.WriteAllLines(Path.Combine(projectFilesPath, $"{Guid.ToString()}.csmap"), sourceGuidToClassName.Select(t => $"{t.Key.ToString("N")}:{t.Value}"));

                List <string> supportedPlatformBuildConditions = new List <string>();
                PopulateSupportedPlatformBuildConditions(supportedPlatformBuildConditions, suportedPlatformBuildConditionTemplate, "InEditor", InEditorPlatforms);
                PopulateSupportedPlatformBuildConditions(supportedPlatformBuildConditions, suportedPlatformBuildConditionTemplate, "Player", PlayerPlatforms);

                HashSet <string>            inEditorSearchPaths = new HashSet <string>(), playerSearchPaths = new HashSet <string>();
                string                      projectReferences = string.Join("\r\n", CreateProjectReferencesSet(projectReferenceSetTemplate, inEditorSearchPaths, true), CreateProjectReferencesSet(projectReferenceSetTemplate, playerSearchPaths, false));
                Dictionary <string, string> tokens = new Dictionary <string, string>()
                {
                    { "<!--PROJECT_GUID_TOKEN-->", Guid.ToString() },
                    { "<!--ALLOW_UNSAFE_TOKEN-->", AssemblyDefinitionInfo.allowUnsafeCode.ToString() },
                    { "<!--LANGUAGE_VERSION_TOKEN-->", MSBuildTools.CSharpVersion },

                    { "<!--DEVELOPMENT_BUILD_TOKEN-->", "false" }, // Default to false

                    { "<!--IS_EDITOR_ONLY_TARGET_TOKEN-->", (ProjectType == ProjectType.EditorAsmDef || ProjectType == ProjectType.PredefinedEditorAssembly).ToString() },
                    { "<!--UNITY_EDITOR_INSTALL_FOLDER-->", Path.GetDirectoryName(EditorApplication.applicationPath) + "\\" },

                    { "<!--DEFAULT_PLATFORM_TOKEN-->", UnityProjectInfo.AvailablePlatforms.First(t => t.BuildTarget == BuildTarget.StandaloneWindows).Name },

                    { "<!--SUPPORTED_PLATFORMS_TOKEN-->", string.Join(";", UnityProjectInfo.AvailablePlatforms.Select(t => t.Name)) },

                    { "<!--INEDITOR_ASSEMBLY_SEARCH_PATHS_TOKEN-->", string.Join(";", inEditorSearchPaths) },
                    { "<!--PLAYER_ASSEMBLY_SEARCH_PATHS_TOKEN-->", string.Join(";", playerSearchPaths) },

                    { "##PLATFORM_PROPS_FOLDER_PATH_TOKEN##", projectFilesPath },

                    { projectReferenceSetTemplate, projectReferences },
                    { sourceIncludeTemplate, string.Join("\r\n", sourceIncludes) },
                    { suportedPlatformBuildConditionTemplate, string.Join("\r\n", supportedPlatformBuildConditions) }
                };

                projectFileTemplateText = Utilities.ReplaceTokens(projectFileTemplateText, tokens, true);
            }
            else
            {
                Debug.LogError("Failed to find ProjectReferenceSet and/or Source_Include templates in the project template file.");
            }

            File.WriteAllText(ReferencePath.AbsolutePath, projectFileTemplateText);
        }
Exemple #4
0
        /// <summary>
        /// Creates an instance of <see cref="AssemblyDefinitionInfo"/> for the default projects (such as Assembly-CSharp)
        /// </summary>
        /// <param name="assembly">The Unity assembly reference.</param>
        /// <returns>A new instance.</returns>
        public static AssemblyDefinitionInfo GetDefaultAssemblyCSharpInfo(Assembly assembly)
        {
            AssemblyDefinitionInfo toReturn = new AssemblyDefinitionInfo()
            {
                IsDefaultAssembly = true, Guid = Guid.NewGuid(), Directory = new DirectoryInfo(Utilities.AssetPath)
            };

            toReturn.assembly   = assembly;
            toReturn.name       = assembly.name;
            toReturn.references = assembly.assemblyReferences.Select(t => t.name).ToArray();
            toReturn.PrecompiledAssemblyReferences = new HashSet <string>();
            return(toReturn);
        }
        /// <summary>
        /// Creates a new instance of the CSProject info.
        /// </summary>
        /// <param name="unityProjectInfo">Instance of parsed unity project info.</param>
        /// <param name="guid">The unique Guid of this reference item.</param>
        /// <param name="assemblyDefinitionInfo">The associated Assembly-Definition info.</param>
        /// <param name="assembly">The Unity assembly object associated with this csproj.</param>
        /// <param name="baseOutputPath">The output path where everything will be outputted.</param>
        internal CSProjectInfo(UnityProjectInfo unityProjectInfo, AssemblyDefinitionInfo assemblyDefinitionInfo, string baseOutputPath)
            : base(unityProjectInfo, assemblyDefinitionInfo.Guid, new Uri(Path.Combine(baseOutputPath, $"{assemblyDefinitionInfo.Name}.csproj")), assemblyDefinitionInfo.Name)
        {
            AssemblyDefinitionInfo = assemblyDefinitionInfo;

            ProjectType = GetProjectType(assemblyDefinitionInfo);

            InEditorPlatforms = GetCompilationPlatforms(true);
            PlayerPlatforms   = GetCompilationPlatforms(false);

            if (InEditorPlatforms.Count == 0 && PlayerPlatforms.Count == 0)
            {
                Debug.LogError($"The assembly project '{Name}' doesn't contain any supported in-editor or player platform targets.");
            }

            ProjectDependencies = new ReadOnlyCollection <CSProjectDependency <CSProjectInfo> >(csProjectDependencies);
        }
        /// <summary>
        /// Creates a new instance of the CSProject info.
        /// </summary>
        /// <param name="unityProjectInfo">Instance of parsed unity project info.</param>
        /// <param name="guid">The unique Guid of this reference item.</param>
        /// <param name="assemblyDefinitionInfo">The associated Assembly-Definition info.</param>
        /// <param name="assembly">The Unity assembly object associated with this csproj.</param>
        internal CSProjectInfo(UnityProjectInfo unityProjectInfo, AssemblyDefinitionInfo assemblyDefinitionInfo)
            : base(unityProjectInfo, assemblyDefinitionInfo.Guid, assemblyDefinitionInfo.Name)
        {
            AssemblyDefinitionInfo = assemblyDefinitionInfo;

            ProjectType = GetProjectType(assemblyDefinitionInfo);

            InEditorPlatforms = GetCompilationPlatforms(true);
            PlayerPlatforms   = GetCompilationPlatforms(false);

            if (InEditorPlatforms.Count == 0 && PlayerPlatforms.Count == 0)
            {
                Debug.LogError($"The assembly project '{Name}' doesn't contain any supported in-editor or player platform targets.");
            }

            ProjectDependencies = new ReadOnlyCollection <CSProjectDependency <CSProjectInfo> >(csProjectDependencies);
            PluginDependencies  = new ReadOnlyCollection <CSProjectDependency <PluginAssemblyInfo> >(pluginAssemblyDependencies);
            WinMDDependencies   = new ReadOnlyCollection <CSProjectDependency <WinMDInfo> >(winmdDependencies);
        }
        private ProjectType GetProjectType(AssemblyDefinitionInfo assemblyDefinitionInfo)
        {
            if (!assemblyDefinitionInfo.IsDefaultAssembly)
            {
                return(assemblyDefinitionInfo.EditorPlatformSupported && !assemblyDefinitionInfo.NonEditorPlatformSupported ? ProjectType.EditorAsmDef : ProjectType.AsmDef);
            }

            switch (assemblyDefinitionInfo.Name)
            {
            case "Assembly-CSharp":
            case "Assembly-CSharp-firstpass":
                return(ProjectType.PredefinedAssembly);

            case "Assembly-CSharp-Editor":
            case "Assembly-CSharp-Editor-firstpass":
                return(ProjectType.PredefinedEditorAssembly);

            default:
                throw new InvalidOperationException($"Predefined assembly '{assemblyDefinitionInfo.Name}' was not recognized, this generally means it should be added to the switch statement in CSProjectInfo:GetProjectType. Treating is as a PredefinedAssembly instead of PredefinedEditorAssembly.");
            }
        }
Exemple #8
0
        private Dictionary <string, CSProjectInfo> CreateUnityProjects()
        {
            // Not all of these will be converted to C# objects, only the ones found to be referenced
            Dictionary <string, AssemblyDefinitionInfo> asmDefInfoMap           = new Dictionary <string, AssemblyDefinitionInfo>();
            SortedSet <AssemblyDefinitionInfo>          asmDefDirectoriesSorted = new SortedSet <AssemblyDefinitionInfo>(Comparer <AssemblyDefinitionInfo> .Create((a, b) => a.Directory.FullName.CompareTo(b.Directory.FullName)));

            HashSet <string> builtInPackagesWithoutSource = new HashSet <string>();

            // Parse the builtInPackagesFirst
            DirectoryInfo builtInPackagesDirectory = new DirectoryInfo(Utilities.BuiltInPackagesPath);

            foreach (DirectoryInfo packageDirectory in builtInPackagesDirectory.GetDirectories())
            {
                FileInfo[] asmDefFiles = packageDirectory.GetFiles("*.asmdef", SearchOption.AllDirectories);

                if (asmDefFiles.Length == 0)
                {
                    builtInPackagesWithoutSource.Add(packageDirectory.Name.ToLower());
                    continue;
                }

                foreach (FileInfo fileInfo in asmDefFiles)
                {
                    AssemblyDefinitionInfo assemblyDefinitionInfo = AssemblyDefinitionInfo.Parse(fileInfo, this, null, true);
                    asmDefDirectoriesSorted.Add(assemblyDefinitionInfo);
                    asmDefInfoMap.Add(Path.GetFileNameWithoutExtension(fileInfo.Name), assemblyDefinitionInfo);
                }
            }

            Dictionary <string, string> packageCacheVersionedMap = new Dictionary <string, string>();

            foreach (string directory in Directory.GetDirectories(Utilities.PackageLibraryCachePath))
            {
                string directoryName = Path.GetFileName(directory);
                packageCacheVersionedMap.Add(directoryName.Split('@')[0], directoryName);
            }

            Dictionary <string, Assembly>      unityAssemblies = CompilationPipeline.GetAssemblies().ToDictionary(t => t.name);
            Dictionary <string, CSProjectInfo> projectsMap     = new Dictionary <string, CSProjectInfo>();
            Queue <string> projectsToProcess = new Queue <string>();

            // Parse the unity assemblies
            foreach (KeyValuePair <string, Assembly> pair in unityAssemblies)
            {
                if (!asmDefInfoMap.TryGetValue(pair.Key, out AssemblyDefinitionInfo assemblyDefinitionInfo))
                {
                    string asmDefPath = CompilationPipeline.GetAssemblyDefinitionFilePathFromAssemblyName(pair.Key);
                    if (string.IsNullOrEmpty(asmDefPath))
                    {
                        if (!pair.Key.StartsWith("Assembly-CSharp"))
                        {
                            throw new InvalidOperationException($"Failed to retrieve AsmDef for script assembly: {pair.Key}");
                        }

                        Guid guid;
                        switch (pair.Key)
                        {
                        case "Assembly-CSharp":
                            guid = config.AssemblyCSharpGuid;
                            break;

                        case "Assembly-CSharp-firstpass":
                            guid = config.AssemblyCSharpFirstPassGuid;
                            break;

                        case "Assembly-CSharp-Editor":
                            guid = config.AssemblyCSharpEditorGuid;
                            break;

                        case "Assembly-CSharp-Editor-firstpass":
                            guid = config.AssemblyCSharpFirstPassEditorGuid;
                            break;

                        default:
                            throw new InvalidOperationException($"Predefined assembly '{assemblyDefinitionInfo.Name}' was not recognized, this generally means it should be added to the switch statement in CSProjectInfo:GetProjectType.");
                        }

                        assemblyDefinitionInfo = AssemblyDefinitionInfo.GetDefaultAssemblyCSharpInfo(pair.Value, guid);
                        projectsToProcess.Enqueue(pair.Key);
                    }
                    else
                    {
                        assemblyDefinitionInfo = AssemblyDefinitionInfo.Parse(new FileInfo(Utilities.GetFullPathFromKnownRelative(asmDefPath)), this, pair.Value);

                        if (asmDefPath.StartsWith("Assets/"))
                        {
                            // Add as mandatory
                            projectsToProcess.Enqueue(pair.Key);
                        }
                    }

                    asmDefDirectoriesSorted.Add(assemblyDefinitionInfo);
                    asmDefInfoMap.Add(pair.Key, assemblyDefinitionInfo);
                }
            }

            // This will parse additional asmdefs that are not part of current compilation set, but we still need
            foreach (string asmdefGuid in AssetDatabase.FindAssets("t:asmdef"))
            {
                string asmDefPath = AssetDatabase.GUIDToAssetPath(asmdefGuid);
                string asmDefKey  = Path.GetFileNameWithoutExtension(asmDefPath);
                if (!asmDefInfoMap.ContainsKey(asmDefKey))
                {
                    AssemblyDefinitionInfo assemblyDefinitionInfo = AssemblyDefinitionInfo.Parse(new FileInfo(Utilities.GetFullPathFromKnownRelative(asmDefPath)), this, null);
                    asmDefDirectoriesSorted.Add(assemblyDefinitionInfo);
                    asmDefInfoMap.Add(asmDefKey, assemblyDefinitionInfo);
                }
            }

            // Now we have all of the assembly definiton files, let's run a quick validation.
            ValidateAndPatchAssemblyDefinitions(asmDefInfoMap);

            int index = 0;

            ProcessSortedAsmDef(asmDefDirectoriesSorted.ToArray(), ref index, (uri) => true, (a) => { });

            while (projectsToProcess.Count > 0)
            {
                string projectKey = projectsToProcess.Dequeue();

                if (!projectsMap.ContainsKey(projectKey))
                {
                    GetProjectInfo(projectsMap, asmDefInfoMap, builtInPackagesWithoutSource, projectKey);
                }
            }

            return(projectsMap);
        }
Exemple #9
0
        private Dictionary <string, CSProjectInfo> CreateUnityProjects(string projectOutputPath)
        {
            // Not all of these will be converted to C# objects, only the ones found to be referenced
            Dictionary <string, AssemblyDefinitionInfo> asmDefInfoMap = new Dictionary <string, AssemblyDefinitionInfo>();
            HashSet <string> builtInPackagesWithoutSource             = new HashSet <string>();

            // Parse the builtInPackagesFirst
            DirectoryInfo builtInPackagesDirectory = new DirectoryInfo(Utilities.BuiltInPackagesPath);

            foreach (DirectoryInfo packageDirectory in builtInPackagesDirectory.GetDirectories())
            {
                FileInfo[] asmDefFiles = packageDirectory.GetFiles("*.asmdef", SearchOption.AllDirectories);

                if (asmDefFiles.Length == 0)
                {
                    builtInPackagesWithoutSource.Add(packageDirectory.Name.ToLower());
                    continue;
                }

                foreach (FileInfo fileInfo in asmDefFiles)
                {
                    AssemblyDefinitionInfo assemblyDefinitionInfo = AssemblyDefinitionInfo.Parse(fileInfo, this, null, true);
                    asmDefInfoMap.Add(Path.GetFileNameWithoutExtension(fileInfo.Name), assemblyDefinitionInfo);
                }
            }

            Dictionary <string, Assembly>      unityAssemblies = CompilationPipeline.GetAssemblies().ToDictionary(t => t.name);
            Dictionary <string, CSProjectInfo> projectsMap     = new Dictionary <string, CSProjectInfo>();
            Queue <string> projectsToProcess = new Queue <string>();

            // Parse the unity assemblies
            foreach (KeyValuePair <string, Assembly> pair in unityAssemblies)
            {
                if (!asmDefInfoMap.TryGetValue(pair.Key, out AssemblyDefinitionInfo assemblyDefinitionInfo))
                {
                    string asmDefPath = CompilationPipeline.GetAssemblyDefinitionFilePathFromAssemblyName(pair.Key);
                    if (string.IsNullOrEmpty(asmDefPath))
                    {
                        if (!pair.Key.StartsWith("Assembly-CSharp"))
                        {
                            throw new InvalidOperationException($"Failed to retrieve AsmDef for script assembly: {pair.Key}");
                        }

                        assemblyDefinitionInfo = AssemblyDefinitionInfo.GetDefaultAssemblyCSharpInfo(pair.Value);
                        projectsToProcess.Enqueue(pair.Key);
                    }
                    else
                    {
                        assemblyDefinitionInfo = AssemblyDefinitionInfo.Parse(new FileInfo(Utilities.GetFullPathFromKnownRelative(asmDefPath)), this, pair.Value);

                        if (asmDefPath.StartsWith("Assets/"))
                        {
                            // Add as mandatory
                            projectsToProcess.Enqueue(pair.Key);
                        }
                    }

                    asmDefInfoMap.Add(pair.Key, assemblyDefinitionInfo);
                }
            }

            while (projectsToProcess.Count > 0)
            {
                string projectKey = projectsToProcess.Dequeue();

                if (!projectsMap.ContainsKey(projectKey))
                {
                    GetProjectInfo(projectsMap, asmDefInfoMap, builtInPackagesWithoutSource, projectKey, projectOutputPath);
                }
            }

            return(projectsMap);
        }