// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using UnrealBuildTool;
using System.Diagnostics;
using Tools.DotNETCommon.CaselessDictionary;
using Tools.DotNETCommon;
using System.Reflection;
namespace AutomationTool
{
public struct SingleTargetProperties
{
public string TargetName;
public TargetRules Rules;
}
///
/// Autodetected project properties.
///
public class ProjectProperties
{
///
/// Full Project path. Must be a .uproject file
///
public FileReference RawProjectPath;
///
/// True if the uproject contains source code.
///
public bool bIsCodeBasedProject;
///
/// List of all targets detected for this project.
///
public Dictionary Targets = new Dictionary();
///
/// List of all Engine ini files for this project
///
public Dictionary EngineConfigs = new Dictionary();
///
/// List of all Game ini files for this project
///
public Dictionary GameConfigs = new Dictionary();
///
/// List of all programs detected for this project.
///
public List Programs = new List();
///
/// Specifies if the target files were generated
///
public bool bWasGenerated = false;
internal ProjectProperties()
{
}
}
///
/// Project related utility functions.
///
public class ProjectUtils
{
private static CaselessDictionary PropertiesCache = new CaselessDictionary();
///
/// Gets a short project name (QAGame, Elemental, etc)
///
/// Full project path.
/// True if a uproject.
/// Short project name
public static string GetShortProjectName(FileReference RawProjectPath)
{
return CommandUtils.GetFilenameWithoutAnyExtensions(RawProjectPath.FullName);
}
///
/// Gets project properties.
///
/// Full project path.
/// Properties of the project.
public static ProjectProperties GetProjectProperties(FileReference RawProjectPath, List ClientTargetPlatforms = null, bool AssetNativizationRequested = false)
{
string ProjectKey = "UE4";
if (RawProjectPath != null)
{
ProjectKey = CommandUtils.ConvertSeparators(PathSeparator.Slash, RawProjectPath.FullName);
}
ProjectProperties Properties;
if (PropertiesCache.TryGetValue(ProjectKey, out Properties) == false)
{
Properties = DetectProjectProperties(RawProjectPath, ClientTargetPlatforms, AssetNativizationRequested);
PropertiesCache.Add(ProjectKey, Properties);
}
return Properties;
}
///
/// Checks if the project is a UProject file with source code.
///
/// Full project path.
/// True if the project is a UProject file with source code.
public static bool IsCodeBasedUProjectFile(FileReference RawProjectPath)
{
return GetProjectProperties(RawProjectPath, null).bIsCodeBasedProject;
}
///
/// Returns a path to the client binaries folder.
///
/// Full project path.
/// Platform type.
/// Path to the binaries folder.
public static string GetProjectClientBinariesFolder(string ProjectClientBinariesPath, UnrealTargetPlatform Platform = UnrealTargetPlatform.Unknown)
{
if (Platform != UnrealTargetPlatform.Unknown)
{
ProjectClientBinariesPath = CommandUtils.CombinePaths(ProjectClientBinariesPath, Platform.ToString());
}
return ProjectClientBinariesPath;
}
private static bool RequiresTempTarget(FileReference RawProjectPath, List ClientTargetPlatforms, bool AssetNativizationRequested)
{
// check to see if we already have a Target.cs file
if (File.Exists (Path.Combine (Path.GetDirectoryName (RawProjectPath.FullName), "Source", RawProjectPath.GetFileNameWithoutExtension() + ".Target.cs")))
{
return false;
}
else if (Directory.Exists(Path.Combine(Path.GetDirectoryName(RawProjectPath.FullName), "Source")))
{
// wasn't one in the main Source directory, let's check all sub-directories
//@todo: may want to read each target.cs to see if it has a target corresponding to the project name as a final check
FileInfo[] Files = (new DirectoryInfo( Path.Combine (Path.GetDirectoryName (RawProjectPath.FullName), "Source")).GetFiles ("*.Target.cs", SearchOption.AllDirectories));
if (Files.Length > 0)
{
return false;
}
}
//
// once we reach this point, we can surmise that this is an asset-
// only (code free) project
if (AssetNativizationRequested)
{
// we're going to be converting some of the project's assets
// into native code, so we require a distinct target (executable)
// be generated for this project
return true;
}
if (ClientTargetPlatforms != null)
{
foreach (UnrealTargetPlatform ClientPlatform in ClientTargetPlatforms)
{
String EncryptionKey;
String[] SigningKeys;
EncryptionAndSigning.ParseEncryptionIni(RawProjectPath.Directory, ClientPlatform, out SigningKeys, out EncryptionKey);
if (SigningKeys != null || !string.IsNullOrEmpty(EncryptionKey))
{
return true;
}
}
}
// no Target file, now check to see if build settings have changed
List TargetPlatforms = ClientTargetPlatforms;
if (ClientTargetPlatforms == null || ClientTargetPlatforms.Count < 1)
{
// No client target platforms, add all in
TargetPlatforms = new List();
foreach (UnrealTargetPlatform TargetPlatformType in Enum.GetValues(typeof(UnrealTargetPlatform)))
{
if (TargetPlatformType != UnrealTargetPlatform.Unknown)
{
TargetPlatforms.Add(TargetPlatformType);
}
}
}
// Change the working directory to be the Engine/Source folder. We are running from Engine/Binaries/DotNET
DirectoryReference oldCWD = DirectoryReference.GetCurrentDirectory();
try
{
DirectoryReference EngineSourceDirectory = DirectoryReference.Combine(CommandUtils.EngineDirectory, "Source");
if (!DirectoryReference.Exists(EngineSourceDirectory)) // only set the directory if it exists, this should only happen if we are launching the editor from an artist sync
{
EngineSourceDirectory = DirectoryReference.Combine(CommandUtils.EngineDirectory, "Binaries");
}
Directory.SetCurrentDirectory(EngineSourceDirectory.FullName);
// Read the project descriptor, and find all the plugins available to this project
ProjectDescriptor Project = ProjectDescriptor.FromFile(RawProjectPath.FullName);
List AvailablePlugins = Plugins.ReadAvailablePlugins(CommandUtils.EngineDirectory, RawProjectPath, Project.AdditionalPluginDirectories);
// check the target platforms for any differences in build settings or additional plugins
bool RetVal = false;
foreach (UnrealTargetPlatform TargetPlatformType in TargetPlatforms)
{
if(!Automation.IsEngineInstalled() && !PlatformExports.HasDefaultBuildConfig(RawProjectPath, TargetPlatformType))
{
RetVal = true;
break;
}
// find if there are any plugins enabled or disabled which differ from the default
foreach(PluginInfo Plugin in AvailablePlugins)
{
bool bPluginEnabledForProject = UProjectInfo.IsPluginEnabledForProject(Plugin, Project, TargetPlatformType, TargetType.Game);
if ((bPluginEnabledForProject && !Plugin.Descriptor.bEnabledByDefault) || (bPluginEnabledForProject && Plugin.Descriptor.bInstalled))
{
// NOTE: this code was only marking plugins that compiled for the platform to upgrade to code project, however
// this doesn't work in practice, because the runtime code will look for the plugin, without a .uplugin file,
// and will fail. This is the safest way to make sure all platforms are acting the same. However, if you
// whitelist the plugin in the .uproject file, the above UProjectInfo.IsPluginEnabledForProject check won't pass
// so you won't get in here. Leaving this commented out code in there, because someone is bound to come looking
// for why a non-whitelisted platform module is causing a project to convert to code-based.
// As an aside, if you run the project with UE4Game (not your Project's binary) from the debugger, it will work
// _in this case_ because the .uplugin file will have been staged, and there is no needed library
// if(Plugin.Descriptor.Modules.Any(Module => Module.IsCompiledInConfiguration(TargetPlatformType, TargetType.Game, bBuildDeveloperTools: false, bBuildEditor: false)))
{
RetVal = true;
break;
}
}
}
}
return RetVal;
}
finally
{
// Change back to the original directory
Directory.SetCurrentDirectory(oldCWD.FullName);
}
}
private static void GenerateTempTarget(FileReference RawProjectPath)
{
// read in the template target cs file
var TempCSFile = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine", "Build", "Target.cs.template");
string TargetCSFile = File.ReadAllText(TempCSFile);
// replace {GAME_NAME} with the game name
TargetCSFile = TargetCSFile.Replace("{GAME_NAME}", Path.GetFileNameWithoutExtension(RawProjectPath.FullName));
// write out the file in a new Source directory
string FileName = CommandUtils.CombinePaths(Path.GetDirectoryName(RawProjectPath.FullName), "Intermediate", "Source", Path.GetFileNameWithoutExtension(RawProjectPath.FullName) + ".Target.cs");
if (!Directory.Exists(Path.GetDirectoryName(FileName)))
{
Directory.CreateDirectory(Path.GetDirectoryName(FileName));
}
File.WriteAllText(FileName, TargetCSFile);
}
///
/// Attempts to autodetect project properties.
///
/// Full project path.
/// Project properties.
private static ProjectProperties DetectProjectProperties(FileReference RawProjectPath, List ClientTargetPlatforms, bool AssetNativizationRequested)
{
var Properties = new ProjectProperties();
Properties.RawProjectPath = RawProjectPath;
// detect if the project is content only, but has non-default build settings
List ExtraSearchPaths = null;
if (RawProjectPath != null)
{
string TempTargetDir = CommandUtils.CombinePaths(Path.GetDirectoryName(RawProjectPath.FullName), "Intermediate", "Source");
if (RequiresTempTarget(RawProjectPath, ClientTargetPlatforms, AssetNativizationRequested))
{
GenerateTempTarget(RawProjectPath);
Properties.bWasGenerated = true;
ExtraSearchPaths = new List();
ExtraSearchPaths.Add(TempTargetDir);
}
else if (File.Exists(Path.Combine(Path.GetDirectoryName(RawProjectPath.FullName), "Intermediate", "Source", Path.GetFileNameWithoutExtension(RawProjectPath.FullName) + ".Target.cs")))
{
File.Delete(Path.Combine(Path.GetDirectoryName(RawProjectPath.FullName), "Intermediate", "Source", Path.GetFileNameWithoutExtension(RawProjectPath.FullName) + ".Target.cs"));
}
// in case the RulesCompiler (what we use to find all the
// Target.cs files) has already cached the contents of this
// directory, then we need to invalidate that cache (so
// it'll find/use the new Target.cs file)
RulesCompiler.InvalidateRulesFileCache(TempTargetDir);
}
if (CommandUtils.CmdEnv.HasCapabilityToCompile)
{
DetectTargetsForProject(Properties, ExtraSearchPaths);
Properties.bIsCodeBasedProject = !CommandUtils.IsNullOrEmpty(Properties.Targets) || !CommandUtils.IsNullOrEmpty(Properties.Programs);
}
else
{
// should never ask for engine targets if we can't compile
if (RawProjectPath == null)
{
throw new AutomationException("Cannot determine engine targets if we can't compile.");
}
Properties.bIsCodeBasedProject = Properties.bWasGenerated;
// if there's a Source directory with source code in it, then mark us as having source code
string SourceDir = CommandUtils.CombinePaths(Path.GetDirectoryName(RawProjectPath.FullName), "Source");
if (Directory.Exists(SourceDir))
{
string[] CppFiles = Directory.GetFiles(SourceDir, "*.cpp", SearchOption.AllDirectories);
string[] HFiles = Directory.GetFiles(SourceDir, "*.h", SearchOption.AllDirectories);
Properties.bIsCodeBasedProject |= (CppFiles.Length > 0 || HFiles.Length > 0);
}
}
// check to see if the uproject loads modules, only if we haven't already determined it is a code based project
if (!Properties.bIsCodeBasedProject && RawProjectPath != null)
{
string uprojectStr = File.ReadAllText(RawProjectPath.FullName);
Properties.bIsCodeBasedProject = uprojectStr.Contains("\"Modules\"");
}
// Get all ini files
if (RawProjectPath != null)
{
CommandUtils.LogVerbose("Loading ini files for {0}", RawProjectPath);
foreach (UnrealTargetPlatform TargetPlatformType in Enum.GetValues(typeof(UnrealTargetPlatform)))
{
if (TargetPlatformType != UnrealTargetPlatform.Unknown)
{
var Config = ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, RawProjectPath.Directory, TargetPlatformType);
Properties.EngineConfigs.Add(TargetPlatformType, Config);
}
}
foreach (UnrealTargetPlatform TargetPlatformType in Enum.GetValues(typeof(UnrealTargetPlatform)))
{
if (TargetPlatformType != UnrealTargetPlatform.Unknown)
{
var Config = ConfigCache.ReadHierarchy(ConfigHierarchyType.Game, RawProjectPath.Directory, TargetPlatformType);
Properties.GameConfigs.Add(TargetPlatformType, Config);
}
}
}
return Properties;
}
///
/// Gets the project's root binaries folder.
///
/// Full project path.
/// Target type.
/// True if uproject file.
/// Binaries path.
public static string GetClientProjectBinariesRootPath(FileReference RawProjectPath, TargetType TargetType, bool bIsCodeBasedProject)
{
var BinPath = String.Empty;
switch (TargetType)
{
case TargetType.Program:
BinPath = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine", "Binaries");
break;
case TargetType.Client:
case TargetType.Game:
if (!bIsCodeBasedProject)
{
BinPath = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine", "Binaries");
}
else
{
BinPath = CommandUtils.CombinePaths(CommandUtils.GetDirectoryName(RawProjectPath.FullName), "Binaries");
}
break;
}
return BinPath;
}
///
/// Gets the location where all rules assemblies should go
///
private static string GetRulesAssemblyFolder()
{
string RulesFolder;
if (GlobalCommandLine.Installed.IsSet)
{
RulesFolder = CommandUtils.CombinePaths(Path.GetTempPath(), "UAT", CommandUtils.EscapePath(CommandUtils.CmdEnv.LocalRoot), "Rules");
}
else
{
RulesFolder = CommandUtils.CombinePaths(CommandUtils.CmdEnv.EngineSavedFolder, "Rules");
}
return RulesFolder;
}
///
/// Finds all targets for the project.
///
/// Project properties.
/// Additional search paths.
private static void DetectTargetsForProject(ProjectProperties Properties, List ExtraSearchPaths = null)
{
Properties.Targets = new Dictionary();
FileReference TargetsDllFilename;
string FullProjectPath = null;
var GameFolders = new List();
var RulesFolder = new DirectoryReference(GetRulesAssemblyFolder());
if (Properties.RawProjectPath != null)
{
CommandUtils.LogVerbose("Looking for targets for project {0}", Properties.RawProjectPath);
TargetsDllFilename = FileReference.Combine(RulesFolder, String.Format("UATRules{0}.dll", Properties.RawProjectPath.GetHashCode()));
FullProjectPath = CommandUtils.GetDirectoryName(Properties.RawProjectPath.FullName);
GameFolders.Add(new DirectoryReference(FullProjectPath));
CommandUtils.LogVerbose("Searching for target rule files in {0}", FullProjectPath);
}
else
{
TargetsDllFilename = FileReference.Combine(RulesFolder, String.Format("UATRules{0}.dll", "_BaseEngine_"));
}
// the UBT code assumes a certain CWD, but artists don't have this CWD.
var SourceDir = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine", "Source");
bool DirPushed = false;
if (CommandUtils.DirectoryExists_NoExceptions(SourceDir))
{
CommandUtils.PushDir(SourceDir);
DirPushed = true;
}
var ExtraSearchDirectories = (ExtraSearchPaths == null)? null : ExtraSearchPaths.Select(x => new DirectoryReference(x)).ToList();
var TargetScripts = RulesCompiler.FindAllRulesSourceFiles(RulesCompiler.RulesFileType.Target, GameFolders: GameFolders, ForeignPlugins: null, AdditionalSearchPaths: ExtraSearchDirectories);
if (DirPushed)
{
CommandUtils.PopDir();
}
if (!CommandUtils.IsNullOrEmpty(TargetScripts))
{
// We only care about project target script so filter out any scripts not in the project folder, or take them all if we are just doing engine stuff
var ProjectTargetScripts = new List();
foreach (var TargetScript in TargetScripts)
{
if (FullProjectPath == null || TargetScript.IsUnderDirectory(new DirectoryReference(FullProjectPath)))
{
ProjectTargetScripts.Add(TargetScript);
}
}
TargetScripts = ProjectTargetScripts;
}
if (!CommandUtils.IsNullOrEmpty(TargetScripts))
{
CommandUtils.LogVerbose("Found {0} target rule files:", TargetScripts.Count);
foreach (var Filename in TargetScripts)
{
CommandUtils.LogVerbose(" {0}", Filename);
}
// Check if the scripts require compilation
bool DoNotCompile = false;
if (!CommandUtils.IsBuildMachine && !CheckIfScriptAssemblyIsOutOfDate(TargetsDllFilename, TargetScripts))
{
Log.TraceVerbose("Targets DLL {0} is up to date.", TargetsDllFilename);
DoNotCompile = true;
}
if (!DoNotCompile && CommandUtils.FileExists_NoExceptions(TargetsDllFilename.FullName))
{
if (!CommandUtils.DeleteFile_NoExceptions(TargetsDllFilename.FullName, true))
{
DoNotCompile = true;
CommandUtils.LogVerbose("Could not delete {0} assuming it is up to date and reusable for a recursive UAT call.", TargetsDllFilename);
}
}
CompileAndLoadTargetsAssembly(Properties, TargetsDllFilename, DoNotCompile, TargetScripts);
}
}
///
/// Optionally compiles and loads target rules assembly.
///
///
///
///
///
private static void CompileAndLoadTargetsAssembly(ProjectProperties Properties, FileReference TargetsDllFilename, bool DoNotCompile, List TargetScripts)
{
CommandUtils.LogVerbose("Compiling targets DLL: {0}", TargetsDllFilename);
var ReferencedAssemblies = new List()
{
"System.dll",
"System.Core.dll",
"System.Xml.dll",
typeof(UnrealBuildTool.PlatformExports).Assembly.Location
};
var TargetsDLL = DynamicCompilation.CompileAndLoadAssembly(TargetsDllFilename, TargetScripts, ReferencedAssemblies, null, DoNotCompile);
var AllCompiledTypes = TargetsDLL.GetTypes();
foreach (Type TargetType in AllCompiledTypes)
{
// Find TargetRules but skip all "UE4Editor", "UE4Game" targets.
if (typeof(TargetRules).IsAssignableFrom(TargetType))
{
string TargetName = GetTargetName(TargetType);
FileReference ProjectFile;
UProjectInfo.TryGetProjectForTarget(TargetName, out ProjectFile);
var DummyTargetInfo = new TargetInfo(TargetName, BuildHostPlatform.Current.Platform, UnrealTargetConfiguration.Development, "", ProjectFile);
// Create an instance of this type
CommandUtils.LogVerbose("Creating target rules object: {0}", TargetType.Name);
var Rules = Activator.CreateInstance(TargetType, DummyTargetInfo) as TargetRules;
CommandUtils.LogVerbose("Adding target: {0} ({1})", TargetType.Name, Rules.Type);
SingleTargetProperties TargetData;
TargetData.TargetName = GetTargetName(TargetType);
TargetData.Rules = Rules;
if (Rules.Type == global::UnrealBuildTool.TargetType.Program)
{
Properties.Programs.Add(TargetData);
}
else
{
Properties.Targets.Add(Rules.Type, TargetData);
}
}
}
}
///
/// Checks if any of the script files in newer than the generated assembly.
///
///
///
/// True if the generated assembly is out of date.
private static bool CheckIfScriptAssemblyIsOutOfDate(FileReference TargetsDllFilename, List TargetScripts)
{
var bOutOfDate = false;
var AssemblyInfo = new FileInfo(TargetsDllFilename.FullName);
if (AssemblyInfo.Exists)
{
foreach (var ScriptFilename in TargetScripts)
{
var ScriptInfo = new FileInfo(ScriptFilename.FullName);
if (ScriptInfo.Exists && ScriptInfo.LastWriteTimeUtc > AssemblyInfo.LastWriteTimeUtc)
{
bOutOfDate = true;
break;
}
}
}
else
{
bOutOfDate = true;
}
return bOutOfDate;
}
///
/// Converts class type name (usually ends with Target) to a target name (without the postfix).
///
/// Tagert class.
/// Target name
private static string GetTargetName(Type TargetRulesType)
{
const string TargetPostfix = "Target";
var Name = TargetRulesType.Name;
if (Name.EndsWith(TargetPostfix, StringComparison.InvariantCultureIgnoreCase))
{
Name = Name.Substring(0, Name.Length - TargetPostfix.Length);
}
return Name;
}
///
/// Performs initial cleanup of target rules folder
///
public static void CleanupFolders()
{
CommandUtils.LogVerbose("Cleaning up project rules folder");
var RulesFolder = GetRulesAssemblyFolder();
if (CommandUtils.DirectoryExists(RulesFolder))
{
CommandUtils.DeleteDirectoryContents(RulesFolder);
}
}
}
public class BranchInfo
{
public static List MonolithicKinds = new List
{
TargetType.Game,
TargetType.Client,
TargetType.Server,
};
[DebuggerDisplay("{GameName}")]
public class BranchUProject
{
public string GameName;
public FileReference FilePath;
public ProjectProperties Properties;
public BranchUProject(UnrealBuildTool.UProjectInfo InfoEntry)
{
GameName = InfoEntry.GameName;
//not sure what the heck this path is relative to
FilePath = InfoEntry.FilePath;
if (!CommandUtils.FileExists_NoExceptions(FilePath.FullName))
{
throw new AutomationException("Could not resolve relative path corrctly {0} -> {1} which doesn't exist.", InfoEntry.FilePath, FilePath);
}
Properties = ProjectUtils.GetProjectProperties(FilePath);
}
public BranchUProject()
{
GameName = "UE4";
Properties = ProjectUtils.GetProjectProperties(null);
if (!Properties.Targets.ContainsKey(TargetType.Editor))
{
throw new AutomationException("Base UE4 project did not contain an editor target.");
}
}
public void Dump(List InHostPlatforms)
{
CommandUtils.LogVerbose(" ShortName: " + GameName);
CommandUtils.LogVerbose(" FilePath : " + FilePath);
CommandUtils.LogVerbose(" bIsCodeBasedProject : " + (Properties.bIsCodeBasedProject ? "YES" : "NO"));
foreach (var HostPlatform in InHostPlatforms)
{
CommandUtils.LogVerbose(" For Host : " + HostPlatform.ToString());
CommandUtils.LogVerbose(" Targets {0}:", Properties.Targets.Count);
foreach (var ThisTarget in Properties.Targets)
{
CommandUtils.LogVerbose(" TargetName : " + ThisTarget.Value.TargetName);
CommandUtils.LogVerbose(" Type : " + ThisTarget.Key.ToString());
CommandUtils.LogVerbose(" bUsesSteam : " + (ThisTarget.Value.Rules.bUsesSteam ? "YES" : "NO"));
CommandUtils.LogVerbose(" bUsesCEF3 : " + (ThisTarget.Value.Rules.bUsesCEF3 ? "YES" : "NO"));
CommandUtils.LogVerbose(" bUsesSlate : " + (ThisTarget.Value.Rules.bUsesSlate ? "YES" : "NO"));
}
CommandUtils.LogVerbose(" Programs {0}:", Properties.Programs.Count);
foreach (var ThisTarget in Properties.Programs)
{
CommandUtils.LogVerbose(" TargetName : " + ThisTarget.TargetName);
}
}
}
};
public BranchUProject BaseEngineProject = null;
public List CodeProjects = new List();
public List NonCodeProjects = new List();
public IEnumerable AllProjects
{
get { return CodeProjects.Union(NonCodeProjects); }
}
public BranchInfo(List InHostPlatforms)
{
BaseEngineProject = new BranchUProject();
var AllProjects = UnrealBuildTool.UProjectInfo.FilterGameProjects(false, null);
using(TelemetryStopwatch SortProjectsStopwatch = new TelemetryStopwatch("SortProjects"))
{
foreach (var InfoEntry in AllProjects)
{
var UProject = new BranchUProject(InfoEntry);
if (UProject.Properties.bIsCodeBasedProject)
{
CodeProjects.Add(UProject);
}
else
{
NonCodeProjects.Add(UProject);
// the base project uses BlankProject if it really needs a .uproject file
if (BaseEngineProject.FilePath == null && UProject.GameName == "BlankProject")
{
BaseEngineProject.FilePath = UProject.FilePath;
}
}
}
}
/* if (String.IsNullOrEmpty(BaseEngineProject.FilePath))
{
throw new AutomationException("All branches must have the blank project /Samples/Sandbox/BlankProject");
}*/
using(TelemetryStopwatch ProjectDumpStopwatch = new TelemetryStopwatch("Project Dump"))
{
CommandUtils.LogVerbose(" Base Engine:");
BaseEngineProject.Dump(InHostPlatforms);
CommandUtils.LogVerbose(" {0} Code projects:", CodeProjects.Count);
foreach (var Proj in CodeProjects)
{
Proj.Dump(InHostPlatforms);
}
CommandUtils.LogVerbose(" {0} Non-Code projects:", CodeProjects.Count);
foreach (var Proj in NonCodeProjects)
{
Proj.Dump(InHostPlatforms);
}
}
}
public BranchUProject FindGame(string GameName)
{
foreach (var Proj in CodeProjects)
{
if (Proj.GameName.Equals(GameName, StringComparison.InvariantCultureIgnoreCase))
{
return Proj;
}
}
foreach (var Proj in NonCodeProjects)
{
if (Proj.GameName.Equals(GameName, StringComparison.InvariantCultureIgnoreCase))
{
return Proj;
}
}
return null;
}
public BranchUProject FindGameChecked(string GameName)
{
BranchUProject Project = FindGame(GameName);
if(Project == null)
{
throw new AutomationException("Cannot find project '{0}' in branch", GameName);
}
return Project;
}
public SingleTargetProperties FindProgram(string ProgramName)
{
foreach (var Proj in BaseEngineProject.Properties.Programs)
{
if (Proj.TargetName.Equals(ProgramName, StringComparison.InvariantCultureIgnoreCase))
{
return Proj;
}
}
foreach (var CodeProj in CodeProjects)
{
foreach (var Proj in CodeProj.Properties.Programs)
{
if (Proj.TargetName.Equals(ProgramName, StringComparison.InvariantCultureIgnoreCase))
{
return Proj;
}
}
}
SingleTargetProperties Result;
Result.TargetName = ProgramName;
Result.Rules = null;
return Result;
}
};
}