// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using EpicGames.Core; namespace UnrealBuildBase { /// /// Utility functions for querying native projects (ie. those found via a .uprojectdirs query) /// public class NativeProjectsBase { /// /// Object used for synchronizing access to static fields /// protected static object LockObject = new object(); /// /// The native project base directories /// static HashSet? CachedBaseDirectories; /// /// Cached list of project files within all the base directories /// static HashSet? CachedProjectFiles; /// /// Clear our cached properties. Generally only needed if your script has modified local files... /// public static void ClearCacheBase() { CachedBaseDirectories = null; CachedProjectFiles = null; } /// /// Retrieve the list of base directories for native projects /// public static IEnumerable EnumerateBaseDirectories() { if(CachedBaseDirectories == null) { lock(LockObject) { if(CachedBaseDirectories == null) { HashSet BaseDirs = new HashSet(); foreach (FileReference RootFile in DirectoryLookupCache.EnumerateFiles(Unreal.RootDirectory)) { if(RootFile.HasExtension(".uprojectdirs")) { foreach(string Line in File.ReadAllLines(RootFile.FullName)) { string TrimLine = Line.Trim(); if(!TrimLine.StartsWith(";")) { DirectoryReference BaseProjectDir = DirectoryReference.Combine(Unreal.RootDirectory, TrimLine); if(BaseProjectDir.IsUnderDirectory(Unreal.RootDirectory)) { BaseDirs.Add(BaseProjectDir); } else { Log.TraceWarning("Project search path '{0}' referenced by '{1}' is not under '{2}', ignoring.", TrimLine, RootFile, Unreal.RootDirectory); } } } } } CachedBaseDirectories = BaseDirs; } } } return CachedBaseDirectories; } /// /// Returns a list of all the projects /// /// List of projects public static IEnumerable EnumerateProjectFiles() { if(CachedProjectFiles == null) { lock(LockObject) { if(CachedProjectFiles == null) { HashSet ProjectFiles = new HashSet(); foreach(DirectoryReference BaseDirectory in EnumerateBaseDirectories()) { if(DirectoryLookupCache.DirectoryExists(BaseDirectory)) { foreach(DirectoryReference SubDirectory in DirectoryLookupCache.EnumerateDirectories(BaseDirectory)) { // Ignore system directories (specifically for Mac, since temporary folders are created here) string DirectoryName = SubDirectory.GetDirectoryName(); if (DirectoryName.StartsWith(".", StringComparison.Ordinal)) { continue; } foreach(FileReference File in DirectoryLookupCache.EnumerateFiles(SubDirectory)) { if(File.HasExtension(".uproject")) { ProjectFiles.Add(File); } } } } } CachedProjectFiles = ProjectFiles; } } } return CachedProjectFiles; } /// /// Finds all target files under a given folder, and add them to the target name to project file map /// /// Directory to search /// Map from target name to project file /// The project file for this directory protected static void FindTargetFiles(DirectoryReference Directory, Dictionary TargetNameToProjectFile, FileReference ProjectFile) { // Search for all target files within this directory bool bSearchSubFolders = true; foreach (FileReference File in DirectoryLookupCache.EnumerateFiles(Directory)) { if (File.HasExtension(".target.cs")) { string TargetName = Path.GetFileNameWithoutExtension(File.GetFileNameWithoutExtension()); TargetNameToProjectFile[TargetName] = ProjectFile; bSearchSubFolders = false; } } // If we didn't find anything, recurse through the subfolders if(bSearchSubFolders) { foreach(DirectoryReference SubDirectory in DirectoryLookupCache.EnumerateDirectories(Directory)) { FindTargetFiles(SubDirectory, TargetNameToProjectFile, ProjectFile); } } } /// /// Checks if a given project is a native project /// /// The project file to check /// True if the given project is a native project public static bool IsNativeProject(FileReference ProjectFile) { EnumerateProjectFiles(); return CachedProjectFiles!.Contains(ProjectFile); } } }