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