public DirectoryCache(DirectoryReference InDirectory) { Directory = InDirectory; Exists = Directory.Exists(); if (!Exists) { Files = new HashSet<FileReference>(); Directories = new HashSet<DirectoryReference>(); } }
/// <summary> /// </summary> public override void CleanProjectFiles(DirectoryReference InMasterProjectDirectory, string InMasterProjectName, DirectoryReference InIntermediateProjectFilesPath) { DirectoryReference MasterProjDeleteFilename = DirectoryReference.Combine(InMasterProjectDirectory, InMasterProjectName + ".xcworkspace"); if (MasterProjDeleteFilename.Exists()) { Directory.Delete(MasterProjDeleteFilename.FullName, true); } // Delete the project files folder if (InIntermediateProjectFilesPath.Exists()) { try { Directory.Delete(InIntermediateProjectFilesPath.FullName, true); } catch (Exception Ex) { Log.TraceInformation("Error while trying to clean project files path {0}. Ignored.", InIntermediateProjectFilesPath); Log.TraceInformation("\t" + Ex.Message); } } }
/// <summary> /// </summary> public override void CleanProjectFiles(DirectoryReference InMasterProjectDirectory, string InMasterProjectName, DirectoryReference InIntermediateProjectFilesDirectory) { FileReference MasterProjectFile = FileReference.Combine(InMasterProjectDirectory, InMasterProjectName); FileReference MasterProjDeleteFilename = MasterProjectFile + ".sln"; if (MasterProjDeleteFilename.Exists()) { MasterProjDeleteFilename.Delete(); } MasterProjDeleteFilename = MasterProjectFile + ".sdf"; if (MasterProjDeleteFilename.Exists()) { MasterProjDeleteFilename.Delete(); } MasterProjDeleteFilename = MasterProjectFile + ".suo"; if (MasterProjDeleteFilename.Exists()) { MasterProjDeleteFilename.Delete(); } MasterProjDeleteFilename = MasterProjectFile + ".v11.suo"; if (MasterProjDeleteFilename.Exists()) { MasterProjDeleteFilename.Delete(); } MasterProjDeleteFilename = MasterProjectFile + ".v12.suo"; if (MasterProjDeleteFilename.Exists()) { MasterProjDeleteFilename.Delete(); } // Delete the project files folder if (InIntermediateProjectFilesDirectory.Exists()) { try { Directory.Delete(InIntermediateProjectFilesDirectory.FullName, true); } catch (Exception Ex) { Log.TraceInformation("Error while trying to clean project files path {0}. Ignored.", InIntermediateProjectFilesDirectory); Log.TraceInformation("\t" + Ex.Message); } } }
private void WriteSchemeFile(string TargetName, string TargetGuid, string BuildTargetGuid, string IndexTargetGuid, bool bHasEditorConfiguration, string GameProjectPath) { string DefaultConfiguration = bHasEditorConfiguration && !XcodeProjectFileGenerator.bGeneratingRunIOSProject && !XcodeProjectFileGenerator.bGeneratingRunTVOSProject ? "Development Editor" : "Development"; var Content = new StringBuilder(); Content.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + ProjectFileGenerator.NewLine); Content.Append("<Scheme" + ProjectFileGenerator.NewLine); Content.Append(" LastUpgradeVersion = \"0710\"" + ProjectFileGenerator.NewLine); Content.Append(" version = \"1.3\">" + ProjectFileGenerator.NewLine); Content.Append(" <BuildAction" + ProjectFileGenerator.NewLine); Content.Append(" parallelizeBuildables = \"YES\"" + ProjectFileGenerator.NewLine); Content.Append(" buildImplicitDependencies = \"YES\">" + ProjectFileGenerator.NewLine); Content.Append(" <BuildActionEntries>" + ProjectFileGenerator.NewLine); Content.Append(" <BuildActionEntry" + ProjectFileGenerator.NewLine); Content.Append(" buildForTesting = \"YES\"" + ProjectFileGenerator.NewLine); Content.Append(" buildForRunning = \"YES\"" + ProjectFileGenerator.NewLine); Content.Append(" buildForProfiling = \"YES\"" + ProjectFileGenerator.NewLine); Content.Append(" buildForArchiving = \"YES\"" + ProjectFileGenerator.NewLine); Content.Append(" buildForAnalyzing = \"YES\">" + ProjectFileGenerator.NewLine); Content.Append(" <BuildableReference" + ProjectFileGenerator.NewLine); Content.Append(" BuildableIdentifier = \"primary\"" + ProjectFileGenerator.NewLine); Content.Append(" BlueprintIdentifier = \"" + TargetGuid + "\"" + ProjectFileGenerator.NewLine); Content.Append(" BuildableName = \"" + TargetName + ".app\"" + ProjectFileGenerator.NewLine); Content.Append(" BlueprintName = \"" + TargetName + "\"" + ProjectFileGenerator.NewLine); Content.Append(" ReferencedContainer = \"container:" + TargetName + ".xcodeproj\">" + ProjectFileGenerator.NewLine); Content.Append(" </BuildableReference>" + ProjectFileGenerator.NewLine); Content.Append(" </BuildActionEntry>" + ProjectFileGenerator.NewLine); Content.Append(" </BuildActionEntries>" + ProjectFileGenerator.NewLine); Content.Append(" </BuildAction>" + ProjectFileGenerator.NewLine); Content.Append(" <TestAction" + ProjectFileGenerator.NewLine); Content.Append(" buildConfiguration = \"" + DefaultConfiguration + "\"" + ProjectFileGenerator.NewLine); Content.Append(" selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"" + ProjectFileGenerator.NewLine); Content.Append(" selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"" + ProjectFileGenerator.NewLine); Content.Append(" shouldUseLaunchSchemeArgsEnv = \"YES\">" + ProjectFileGenerator.NewLine); Content.Append(" <Testables>" + ProjectFileGenerator.NewLine); Content.Append(" </Testables>" + ProjectFileGenerator.NewLine); Content.Append(" <MacroExpansion>" + ProjectFileGenerator.NewLine); Content.Append(" <BuildableReference" + ProjectFileGenerator.NewLine); Content.Append(" BuildableIdentifier = \"primary\"" + ProjectFileGenerator.NewLine); Content.Append(" BlueprintIdentifier = \"" + TargetGuid + "\"" + ProjectFileGenerator.NewLine); Content.Append(" BuildableName = \"" + TargetName + ".app\"" + ProjectFileGenerator.NewLine); Content.Append(" BlueprintName = \"" + TargetName + "\"" + ProjectFileGenerator.NewLine); Content.Append(" ReferencedContainer = \"container:" + TargetName + ".xcodeproj\">" + ProjectFileGenerator.NewLine); Content.Append(" </BuildableReference>" + ProjectFileGenerator.NewLine); Content.Append(" </MacroExpansion>" + ProjectFileGenerator.NewLine); Content.Append(" <AdditionalOptions>" + ProjectFileGenerator.NewLine); Content.Append(" </AdditionalOptions>" + ProjectFileGenerator.NewLine); Content.Append(" </TestAction>" + ProjectFileGenerator.NewLine); Content.Append(" <LaunchAction" + ProjectFileGenerator.NewLine); Content.Append(" buildConfiguration = \"" + DefaultConfiguration + "\"" + ProjectFileGenerator.NewLine); Content.Append(" selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"" + ProjectFileGenerator.NewLine); Content.Append(" selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"" + ProjectFileGenerator.NewLine); Content.Append(" launchStyle = \"0\"" + ProjectFileGenerator.NewLine); Content.Append(" useCustomWorkingDirectory = \"NO\"" + ProjectFileGenerator.NewLine); Content.Append(" ignoresPersistentStateOnLaunch = \"NO\"" + ProjectFileGenerator.NewLine); Content.Append(" debugDocumentVersioning = \"YES\"" + ProjectFileGenerator.NewLine); Content.Append(" debugServiceExtension = \"internal\"" + ProjectFileGenerator.NewLine); Content.Append(" allowLocationSimulation = \"YES\">" + ProjectFileGenerator.NewLine); Content.Append(" <BuildableProductRunnable" + ProjectFileGenerator.NewLine); Content.Append(" runnableDebuggingMode = \"0\">" + ProjectFileGenerator.NewLine); Content.Append(" <BuildableReference" + ProjectFileGenerator.NewLine); Content.Append(" BuildableIdentifier = \"primary\"" + ProjectFileGenerator.NewLine); Content.Append(" BlueprintIdentifier = \"" + TargetGuid + "\"" + ProjectFileGenerator.NewLine); Content.Append(" BuildableName = \"" + TargetName + ".app\"" + ProjectFileGenerator.NewLine); Content.Append(" BlueprintName = \"" + TargetName + "\"" + ProjectFileGenerator.NewLine); Content.Append(" ReferencedContainer = \"container:" + TargetName + ".xcodeproj\">" + ProjectFileGenerator.NewLine); Content.Append(" </BuildableReference>" + ProjectFileGenerator.NewLine); Content.Append(" </BuildableProductRunnable>" + ProjectFileGenerator.NewLine); if (bHasEditorConfiguration && TargetName != "UE4") { Content.Append(" <CommandLineArguments>" + ProjectFileGenerator.NewLine); if (IsForeignProject) { Content.Append(" <CommandLineArgument" + ProjectFileGenerator.NewLine); Content.Append(" argument = \""" + GameProjectPath + ""\"" + ProjectFileGenerator.NewLine); Content.Append(" isEnabled = \"YES\">" + ProjectFileGenerator.NewLine); Content.Append(" </CommandLineArgument>" + ProjectFileGenerator.NewLine); } else { Content.Append(" <CommandLineArgument" + ProjectFileGenerator.NewLine); Content.Append(" argument = \"" + TargetName + "\"" + ProjectFileGenerator.NewLine); Content.Append(" isEnabled = \"YES\">" + ProjectFileGenerator.NewLine); Content.Append(" </CommandLineArgument>" + ProjectFileGenerator.NewLine); } Content.Append(" </CommandLineArguments>" + ProjectFileGenerator.NewLine); } Content.Append(" <AdditionalOptions>" + ProjectFileGenerator.NewLine); Content.Append(" </AdditionalOptions>" + ProjectFileGenerator.NewLine); Content.Append(" </LaunchAction>" + ProjectFileGenerator.NewLine); Content.Append(" <ProfileAction" + ProjectFileGenerator.NewLine); Content.Append(" buildConfiguration = \"" + DefaultConfiguration + "\"" + ProjectFileGenerator.NewLine); Content.Append(" shouldUseLaunchSchemeArgsEnv = \"YES\"" + ProjectFileGenerator.NewLine); Content.Append(" savedToolIdentifier = \"\"" + ProjectFileGenerator.NewLine); Content.Append(" useCustomWorkingDirectory = \"NO\"" + ProjectFileGenerator.NewLine); Content.Append(" debugDocumentVersioning = \"YES\">" + ProjectFileGenerator.NewLine); Content.Append(" <BuildableProductRunnable" + ProjectFileGenerator.NewLine); Content.Append(" runnableDebuggingMode = \"0\">" + ProjectFileGenerator.NewLine); Content.Append(" <BuildableReference" + ProjectFileGenerator.NewLine); Content.Append(" BuildableIdentifier = \"primary\"" + ProjectFileGenerator.NewLine); Content.Append(" BlueprintIdentifier = \"" + TargetGuid + "\"" + ProjectFileGenerator.NewLine); Content.Append(" BuildableName = \"" + TargetName + ".app\"" + ProjectFileGenerator.NewLine); Content.Append(" BlueprintName = \"" + TargetName + "\"" + ProjectFileGenerator.NewLine); Content.Append(" ReferencedContainer = \"container:" + TargetName + ".xcodeproj\">" + ProjectFileGenerator.NewLine); Content.Append(" </BuildableReference>" + ProjectFileGenerator.NewLine); Content.Append(" </BuildableProductRunnable>" + ProjectFileGenerator.NewLine); Content.Append(" </ProfileAction>" + ProjectFileGenerator.NewLine); Content.Append(" <AnalyzeAction" + ProjectFileGenerator.NewLine); Content.Append(" buildConfiguration = \"" + DefaultConfiguration + "\">" + ProjectFileGenerator.NewLine); Content.Append(" </AnalyzeAction>" + ProjectFileGenerator.NewLine); Content.Append(" <ArchiveAction" + ProjectFileGenerator.NewLine); Content.Append(" buildConfiguration = \"" + DefaultConfiguration + "\"" + ProjectFileGenerator.NewLine); Content.Append(" revealArchiveInOrganizer = \"YES\">" + ProjectFileGenerator.NewLine); Content.Append(" </ArchiveAction>" + ProjectFileGenerator.NewLine); Content.Append("</Scheme>" + ProjectFileGenerator.NewLine); DirectoryReference SchemesDir = new DirectoryReference(ProjectFilePath.FullName + "/xcshareddata/xcschemes"); if (!SchemesDir.Exists()) { SchemesDir.CreateDirectory(); } string SchemeFilePath = SchemesDir + "/" + TargetName + ".xcscheme"; File.WriteAllText(SchemeFilePath, Content.ToString(), new UTF8Encoding()); Content.Clear(); Content.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + ProjectFileGenerator.NewLine); Content.Append("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">" + ProjectFileGenerator.NewLine); Content.Append("<plist version=\"1.0\">" + ProjectFileGenerator.NewLine); Content.Append("<dict>" + ProjectFileGenerator.NewLine); Content.Append("\t<key>SchemeUserState</key>" + ProjectFileGenerator.NewLine); Content.Append("\t<dict>" + ProjectFileGenerator.NewLine); Content.Append("\t\t<key>" + TargetName + ".xcscheme_^#shared#^_</key>" + ProjectFileGenerator.NewLine); Content.Append("\t\t<dict>" + ProjectFileGenerator.NewLine); Content.Append("\t\t\t<key>orderHint</key>" + ProjectFileGenerator.NewLine); Content.Append("\t\t\t<integer>" + SchemeOrderHint.ToString() + "</integer>" + ProjectFileGenerator.NewLine); Content.Append("\t\t</dict>" + ProjectFileGenerator.NewLine); Content.Append("\t</dict>" + ProjectFileGenerator.NewLine); Content.Append("\t<key>SuppressBuildableAutocreation</key>" + ProjectFileGenerator.NewLine); Content.Append("\t<dict>" + ProjectFileGenerator.NewLine); Content.Append("\t\t<key>" + TargetGuid + "</key>" + ProjectFileGenerator.NewLine); Content.Append("\t\t<dict>" + ProjectFileGenerator.NewLine); Content.Append("\t\t\t<key>primary</key>" + ProjectFileGenerator.NewLine); Content.Append("\t\t\t<true/>" + ProjectFileGenerator.NewLine); Content.Append("\t\t</dict>" + ProjectFileGenerator.NewLine); Content.Append("\t\t<key>" + BuildTargetGuid + "</key>" + ProjectFileGenerator.NewLine); Content.Append("\t\t<dict>" + ProjectFileGenerator.NewLine); Content.Append("\t\t\t<key>primary</key>" + ProjectFileGenerator.NewLine); Content.Append("\t\t\t<true/>" + ProjectFileGenerator.NewLine); Content.Append("\t\t</dict>" + ProjectFileGenerator.NewLine); Content.Append("\t\t<key>" + IndexTargetGuid + "</key>" + ProjectFileGenerator.NewLine); Content.Append("\t\t<dict>" + ProjectFileGenerator.NewLine); Content.Append("\t\t\t<key>primary</key>" + ProjectFileGenerator.NewLine); Content.Append("\t\t\t<true/>" + ProjectFileGenerator.NewLine); Content.Append("\t\t</dict>" + ProjectFileGenerator.NewLine); Content.Append("\t</dict>" + ProjectFileGenerator.NewLine); Content.Append("</dict>" + ProjectFileGenerator.NewLine); Content.Append("</plist>" + ProjectFileGenerator.NewLine); DirectoryReference ManagementFileDir = new DirectoryReference(ProjectFilePath.FullName + "/xcuserdata/" + Environment.UserName + ".xcuserdatad/xcschemes"); if (!ManagementFileDir.Exists()) { ManagementFileDir.CreateDirectory(); } string ManagementFilePath = ManagementFileDir + "/xcschememanagement.plist"; File.WriteAllText(ManagementFilePath, Content.ToString(), new UTF8Encoding()); SchemeOrderHint++; }
public override void ExecuteBuild() { // Get the plugin filename string PluginParam = ParseParamValue("Plugin"); if(PluginParam == null) { throw new AutomationException("Missing -Plugin=... argument"); } // Check it exists FileReference PluginFile = new FileReference(PluginParam); if (!PluginFile.Exists()) { throw new AutomationException("Plugin '{0}' not found", PluginFile.FullName); } // Get the output directory string PackageParam = ParseParamValue("Package"); if (PackageParam == null) { throw new AutomationException("Missing -Package=... argument"); } // Make sure the packaging directory is valid DirectoryReference PackageDir = new DirectoryReference(PackageParam); if (PluginFile.IsUnderDirectory(PackageDir)) { throw new AutomationException("Packaged plugin output directory must be different to source"); } if (PackageDir.IsUnderDirectory(DirectoryReference.Combine(CommandUtils.RootDirectory, "Engine"))) { throw new AutomationException("Output directory for packaged plugin must be outside engine directory"); } // Clear the output directory of existing stuff if (PackageDir.Exists()) { CommandUtils.DeleteDirectoryContents(PackageDir.FullName); } else { PackageDir.CreateDirectory(); } // Create a placeholder FilterPlugin.ini with instructions on how to use it FileReference SourceFilterFile = FileReference.Combine(PluginFile.Directory, "Config", "FilterPlugin.ini"); if (!SourceFilterFile.Exists()) { List<string> Lines = new List<string>(); Lines.Add("[FilterPlugin]"); Lines.Add("; This section lists additional files which will be packaged along with your plugin. Paths should be listed relative to the root plugin directory, and"); Lines.Add("; may include \"...\", \"*\", and \"?\" wildcards to match directories, files, and individual characters respectively."); Lines.Add(";"); Lines.Add("; Examples:"); Lines.Add("; /README.txt"); Lines.Add("; /Extras/..."); Lines.Add("; /Binaries/ThirdParty/*.dll"); SourceFilterFile.Directory.CreateDirectory(); CommandUtils.WriteAllLines_NoExceptions(SourceFilterFile.FullName, Lines.ToArray()); } // Create a host project for the plugin. For script generator plugins, we need to have UHT be able to load it, which can only happen if it's enabled in a project. FileReference HostProjectFile = FileReference.Combine(PackageDir, "HostProject", "HostProject.uproject"); FileReference HostProjectPluginFile = CreateHostProject(HostProjectFile, PluginFile); // Read the plugin CommandUtils.Log("Reading plugin from {0}...", HostProjectPluginFile); PluginDescriptor Plugin = PluginDescriptor.FromFile(HostProjectPluginFile, false); // Compile the plugin for all the target platforms List<UnrealTargetPlatform> HostPlatforms = ParseParam("NoHostPlatform")? new List<UnrealTargetPlatform>() : new List<UnrealTargetPlatform> { BuildHostPlatform.Current.Platform }; List<UnrealTargetPlatform> TargetPlatforms = GetTargetPlatforms(this, BuildHostPlatform.Current.Platform).Where(x => IsCodeTargetPlatform(BuildHostPlatform.Current.Platform, x)).ToList(); FileReference[] BuildProducts = CompilePlugin(HostProjectFile, HostProjectPluginFile, Plugin, HostPlatforms, TargetPlatforms, ""); // Package up the final plugin data PackagePlugin(HostProjectPluginFile, BuildProducts, PackageDir); // Remove the host project if(!ParseParam("NoDeleteHostProject")) { CommandUtils.DeleteDirectory(HostProjectFile.Directory.FullName); } }
public override void GetFilesToDeployOrStage(ProjectParams Params, DeploymentContext SC) { // Stage all the build products foreach (StageTarget Target in SC.StageTargets) { SC.StageBuildProductsFromReceipt(Target.Receipt, Target.RequireFilesExist, Params.bTreatNonShippingBinariesAsDebugFiles); } if (SC.bStageCrashReporter) { StagedDirectoryReference CrashReportClientPath = StagedDirectoryReference.Combine("Engine/Binaries", SC.PlatformDir, "CrashReportClient.app"); StageAppBundle(SC, DirectoryReference.Combine(SC.LocalRoot, "Engine/Binaries", SC.PlatformDir, "CrashReportClient.app"), CrashReportClientPath); } // Find the app bundle path List <FileReference> Exes = GetExecutableNames(SC); foreach (var Exe in Exes) { StagedDirectoryReference AppBundlePath = null; if (Exe.IsUnderDirectory(DirectoryReference.Combine(SC.RuntimeProjectRootDir, "Binaries", SC.PlatformDir))) { AppBundlePath = StagedDirectoryReference.Combine(SC.ShortProjectName, "Binaries", SC.PlatformDir, Path.GetFileNameWithoutExtension(Exe.FullName) + ".app"); } else if (Exe.IsUnderDirectory(DirectoryReference.Combine(SC.RuntimeRootDir, "Engine/Binaries", SC.PlatformDir))) { AppBundlePath = StagedDirectoryReference.Combine("Engine/Binaries", SC.PlatformDir, Path.GetFileNameWithoutExtension(Exe.FullName) + ".app"); } // Copy the custom icon and Steam dylib, if needed if (AppBundlePath != null) { FileReference AppIconsFile = FileReference.Combine(SC.ProjectRoot, "Build", "Mac", "Application.icns"); if (FileReference.Exists(AppIconsFile)) { SC.StageFile(StagedFileType.NonUFS, AppIconsFile, StagedFileReference.Combine(AppBundlePath, "Contents", "Resources", "Application.icns")); } } } // Copy the splash screen, Mac specific FileReference SplashImage = FileReference.Combine(SC.ProjectRoot, "Content", "Splash", "Splash.bmp"); if (FileReference.Exists(SplashImage)) { SC.StageFile(StagedFileType.NonUFS, SplashImage); } // Stage the bootstrap executable if (!Params.NoBootstrapExe) { foreach (StageTarget Target in SC.StageTargets) { BuildProduct Executable = Target.Receipt.BuildProducts.FirstOrDefault(x => x.Type == BuildProductType.Executable); if (Executable != null) { // only create bootstraps for executables List <StagedFileReference> StagedFiles = SC.FilesToStage.NonUFSFiles.Where(x => x.Value == Executable.Path).Select(x => x.Key).ToList(); if (StagedFiles.Count > 0 && Executable.Path.FullName.Replace("\\", "/").Contains("/" + TargetPlatformType.ToString() + "/")) { string BootstrapArguments = ""; if (!ShouldStageCommandLine(Params, SC)) { if (!SC.IsCodeBasedProject) { BootstrapArguments = String.Format("../../../{0}/{0}.uproject", SC.ShortProjectName); } else { BootstrapArguments = SC.ShortProjectName; } } string BootstrapExeName; if (SC.StageTargetConfigurations.Count > 1) { BootstrapExeName = Path.GetFileName(Executable.Path.FullName) + ".app"; } else if (Params.IsCodeBasedProject) { BootstrapExeName = Target.Receipt.TargetName + ".app"; } else { BootstrapExeName = SC.ShortProjectName + ".app"; } string AppPath = Executable.Path.FullName.Substring(0, Executable.Path.FullName.LastIndexOf(".app/") + 4); foreach (var DestPath in StagedFiles) { string AppRelativePath = DestPath.Name.Substring(0, DestPath.Name.LastIndexOf(".app/") + 4); StageBootstrapExecutable(SC, BootstrapExeName, AppPath, AppRelativePath, BootstrapArguments); } } } } } // Copy the ShaderCache files, if they exist FileReference DrawCacheFile = FileReference.Combine(SC.ProjectRoot, "Content", "DrawCache.ushadercache"); if (FileReference.Exists(DrawCacheFile)) { SC.StageFile(StagedFileType.UFS, DrawCacheFile); } FileReference ByteCodeCacheFile = FileReference.Combine(SC.ProjectRoot, "Content", "ByteCodeCache.ushadercode"); if (FileReference.Exists(ByteCodeCacheFile)) { SC.StageFile(StagedFileType.UFS, ByteCodeCacheFile); } { // Stage any *.metallib files as NonUFS. // Get the final output directory for cooked data DirectoryReference CookOutputDir; if (!String.IsNullOrEmpty(Params.CookOutputDir)) { CookOutputDir = DirectoryReference.Combine(new DirectoryReference(Params.CookOutputDir), SC.CookPlatform); } else if (Params.CookInEditor) { CookOutputDir = DirectoryReference.Combine(SC.ProjectRoot, "Saved", "EditorCooked", SC.CookPlatform); } else { CookOutputDir = DirectoryReference.Combine(SC.ProjectRoot, "Saved", "Cooked", SC.CookPlatform); } if (DirectoryReference.Exists(CookOutputDir)) { List <FileReference> CookedFiles = DirectoryReference.EnumerateFiles(CookOutputDir, "*.metallib", SearchOption.AllDirectories).ToList(); foreach (FileReference CookedFile in CookedFiles) { SC.StageFile(StagedFileType.NonUFS, CookedFile, new StagedFileReference(CookedFile.MakeRelativeTo(CookOutputDir))); } } } }
void StageBootstrapExecutable(DeploymentContext SC, string ExeName, string TargetFile, string StagedRelativeTargetPath, string StagedArguments) { DirectoryReference InputApp = DirectoryReference.Combine(SC.LocalRoot, "Engine", "Binaries", SC.PlatformDir, "BootstrapPackagedGame.app"); if (InternalUtils.SafeDirectoryExists(InputApp.FullName)) { // Create the new bootstrap program DirectoryReference IntermediateDir = DirectoryReference.Combine(SC.ProjectRoot, "Intermediate", "Staging"); InternalUtils.SafeCreateDirectory(IntermediateDir.FullName); DirectoryReference IntermediateApp = DirectoryReference.Combine(IntermediateDir, ExeName); if (DirectoryReference.Exists(IntermediateApp)) { DirectoryReference.Delete(IntermediateApp, true); } CloneDirectory(InputApp.FullName, IntermediateApp.FullName); // Rename the executable string GameName = Path.GetFileNameWithoutExtension(ExeName); FileReference.Move(FileReference.Combine(IntermediateApp, "Contents", "MacOS", "BootstrapPackagedGame"), FileReference.Combine(IntermediateApp, "Contents", "MacOS", GameName)); // Copy the icon string SrcInfoPlistPath = CombinePaths(TargetFile, "Contents", "Info.plist"); string SrcInfoPlist = File.ReadAllText(SrcInfoPlistPath); string IconName = GetValueFromInfoPlist(SrcInfoPlist, "CFBundleIconFile"); if (!string.IsNullOrEmpty(IconName)) { string IconPath = CombinePaths(TargetFile, "Contents", "Resources", IconName + ".icns"); InternalUtils.SafeCreateDirectory(CombinePaths(IntermediateApp.FullName, "Contents", "Resources")); File.Copy(IconPath, CombinePaths(IntermediateApp.FullName, "Contents", "Resources", IconName + ".icns")); } // Update Info.plist contents string DestInfoPlistPath = CombinePaths(IntermediateApp.FullName, "Contents", "Info.plist"); string DestInfoPlist = File.ReadAllText(DestInfoPlistPath); string AppIdentifier = GetValueFromInfoPlist(SrcInfoPlist, "CFBundleIdentifier"); if (AppIdentifier == "com.epicgames.UE4Game") { AppIdentifier = ""; } string Copyright = GetValueFromInfoPlist(SrcInfoPlist, "NSHumanReadableCopyright"); string BundleVersion = GetValueFromInfoPlist(SrcInfoPlist, "CFBundleVersion", "1"); string ShortVersion = GetValueFromInfoPlist(SrcInfoPlist, "CFBundleShortVersionString", "1.0"); DestInfoPlist = DestInfoPlist.Replace("com.epicgames.BootstrapPackagedGame", string.IsNullOrEmpty(AppIdentifier) ? "com.epicgames." + GameName + "_bootstrap" : AppIdentifier + "_bootstrap"); DestInfoPlist = DestInfoPlist.Replace("BootstrapPackagedGame", GameName); DestInfoPlist = DestInfoPlist.Replace("__UE4_ICON_FILE__", IconName); DestInfoPlist = DestInfoPlist.Replace("__UE4_APP_TO_LAUNCH__", StagedRelativeTargetPath); DestInfoPlist = DestInfoPlist.Replace("__UE4_COMMANDLINE__", StagedArguments); DestInfoPlist = DestInfoPlist.Replace("__UE4_COPYRIGHT__", Copyright); DestInfoPlist = DestInfoPlist.Replace("__UE4_BUNDLE_VERSION__", BundleVersion); DestInfoPlist = DestInfoPlist.Replace("__UE4_SHORT_VERSION__", ShortVersion); File.WriteAllText(DestInfoPlistPath, DestInfoPlist); StageAppBundle(SC, IntermediateApp, new StagedDirectoryReference(ExeName)); } }
/// <summary> /// Main entry point for the command /// </summary> public override void ExecuteBuild() { // Build a lookup of flags to set and clear for each identifier Dictionary <string, int> IdentifierToIndex = new Dictionary <string, int>(); for (int Idx = 0; Idx < MacroPairs.GetLength(0); Idx++) { IdentifierToIndex[MacroPairs[Idx, 0]] = Idx; IdentifierToIndex[MacroPairs[Idx, 1]] = ~Idx; } // Check if we want to just parse a single file string FileParam = ParseParamValue("File"); if (FileParam != null) { // Check the file exists FileReference File = new FileReference(FileParam); if (!FileReference.Exists(File)) { throw new AutomationException("File '{0}' does not exist", File); } CheckSourceFile(File, IdentifierToIndex, new object()); } else { // Add the additional files to be ignored foreach (string IgnoreFileName in ParseParamValues("Ignore")) { IgnoreFileNames.Add(IgnoreFileName); } // Create a list of all the root directories HashSet <DirectoryReference> RootDirs = new HashSet <DirectoryReference>(); RootDirs.Add(EngineDirectory); // Add the enterprise directory DirectoryReference EnterpriseDirectory = DirectoryReference.Combine(RootDirectory, "Enterprise"); if (DirectoryReference.Exists(EnterpriseDirectory)) { RootDirs.Add(EnterpriseDirectory); } // Add the project directories string[] ProjectParams = ParseParamValues("Project"); foreach (string ProjectParam in ProjectParams) { FileReference ProjectFile = new FileReference(ProjectParam); if (!FileReference.Exists(ProjectFile)) { throw new AutomationException("Unable to find project '{0}'", ProjectFile); } RootDirs.Add(ProjectFile.Directory); } // Recurse through the tree LogInformation("Finding source files..."); List <FileReference> SourceFiles = new List <FileReference>(); using (ThreadPoolWorkQueue Queue = new ThreadPoolWorkQueue()) { foreach (DirectoryReference RootDir in RootDirs) { DirectoryInfo PluginsDir = new DirectoryInfo(Path.Combine(RootDir.FullName, "Plugins")); if (PluginsDir.Exists) { Queue.Enqueue(() => FindSourceFiles(PluginsDir, SourceFiles, Queue)); } DirectoryInfo SourceDir = new DirectoryInfo(Path.Combine(RootDir.FullName, "Source")); if (SourceDir.Exists) { Queue.Enqueue(() => FindSourceFiles(SourceDir, SourceFiles, Queue)); } } Queue.Wait(); } // Loop through all the source files using (ThreadPoolWorkQueue Queue = new ThreadPoolWorkQueue()) { object LogLock = new object(); foreach (FileReference SourceFile in SourceFiles) { Queue.Enqueue(() => CheckSourceFile(SourceFile, IdentifierToIndex, LogLock)); } using (LogStatusScope Scope = new LogStatusScope("Checking source files...")) { while (!Queue.Wait(10 * 1000)) { Scope.SetProgress("{0}/{1}", SourceFiles.Count - Queue.NumRemaining, SourceFiles.Count); } } } } }
public override void ExecuteBuild() { // Get the plugin filename string PluginParam = ParseParamValue("Plugin"); if (PluginParam == null) { throw new AutomationException("Missing -Plugin=... argument"); } // Check it exists FileReference PluginFile = new FileReference(PluginParam); if (!FileReference.Exists(PluginFile)) { throw new AutomationException("Plugin '{0}' not found", PluginFile.FullName); } // Get the output directory string PackageParam = ParseParamValue("Package"); if (PackageParam == null) { throw new AutomationException("Missing -Package=... argument"); } // Make sure the packaging directory is valid DirectoryReference PackageDir = new DirectoryReference(PackageParam); if (PluginFile.IsUnderDirectory(PackageDir)) { throw new AutomationException("Packaged plugin output directory must be different to source"); } if (PackageDir.IsUnderDirectory(DirectoryReference.Combine(CommandUtils.RootDirectory, "Engine"))) { throw new AutomationException("Output directory for packaged plugin must be outside engine directory"); } // Clear the output directory of existing stuff if (DirectoryReference.Exists(PackageDir)) { CommandUtils.DeleteDirectoryContents(PackageDir.FullName); } else { DirectoryReference.CreateDirectory(PackageDir); } // Create a placeholder FilterPlugin.ini with instructions on how to use it FileReference SourceFilterFile = FileReference.Combine(PluginFile.Directory, "Config", "FilterPlugin.ini"); if (!FileReference.Exists(SourceFilterFile)) { List <string> Lines = new List <string>(); Lines.Add("[FilterPlugin]"); Lines.Add("; This section lists additional files which will be packaged along with your plugin. Paths should be listed relative to the root plugin directory, and"); Lines.Add("; may include \"...\", \"*\", and \"?\" wildcards to match directories, files, and individual characters respectively."); Lines.Add(";"); Lines.Add("; Examples:"); Lines.Add("; /README.txt"); Lines.Add("; /Extras/..."); Lines.Add("; /Binaries/ThirdParty/*.dll"); DirectoryReference.CreateDirectory(SourceFilterFile.Directory); CommandUtils.WriteAllLines_NoExceptions(SourceFilterFile.FullName, Lines.ToArray()); } // Create a host project for the plugin. For script generator plugins, we need to have UHT be able to load it, which can only happen if it's enabled in a project. FileReference HostProjectFile = FileReference.Combine(PackageDir, "HostProject", "HostProject.uproject"); FileReference HostProjectPluginFile = CreateHostProject(HostProjectFile, PluginFile); // Read the plugin CommandUtils.Log("Reading plugin from {0}...", HostProjectPluginFile); PluginDescriptor Plugin = PluginDescriptor.FromFile(HostProjectPluginFile); // Compile the plugin for all the target platforms List <UnrealTargetPlatform> HostPlatforms = ParseParam("NoHostPlatform")? new List <UnrealTargetPlatform>() : new List <UnrealTargetPlatform> { BuildHostPlatform.Current.Platform }; List <UnrealTargetPlatform> TargetPlatforms = GetTargetPlatforms(this, BuildHostPlatform.Current.Platform); FileReference[] BuildProducts = CompilePlugin(HostProjectFile, HostProjectPluginFile, Plugin, HostPlatforms, TargetPlatforms, ""); // Package up the final plugin data PackagePlugin(HostProjectPluginFile, BuildProducts, PackageDir, ParseParam("unversioned")); // Remove the host project if (!ParseParam("NoDeleteHostProject")) { CommandUtils.DeleteDirectory(HostProjectFile.Directory.FullName); } }
public override void ExecuteBuild() { string[] ProjectParams = ParseParamValues("Project"); string UpdateDirParam = ParseParamValue("UpdateDir", null); if (UpdateDirParam == null) { throw new AutomationException("Missing -UpdateDir=... parameter"); } DirectoryReference UpdateDir = new DirectoryReference(UpdateDirParam); bool bWrite = ParseParam("Write"); // Get all the root dirs HashSet <DirectoryReference> RootDirs = new HashSet <DirectoryReference>(); RootDirs.Add(EngineDirectory); // Add the enterprise edirectory DirectoryReference EnterpriseDirectory = DirectoryReference.Combine(RootDirectory, "Enterprise"); if (DirectoryReference.Exists(EnterpriseDirectory)) { RootDirs.Add(EnterpriseDirectory); } // Add the project directories foreach (string ProjectParam in ProjectParams) { FileReference ProjectLocation = new FileReference(ProjectParam); if (!FileReference.Exists(ProjectLocation)) { throw new AutomationException("Unable to find project '{0}'", ProjectLocation); } RootDirs.Add(ProjectLocation.Directory); } // Find all the modules HashSet <DirectoryReference> ModuleDirs = new HashSet <DirectoryReference>(); foreach (DirectoryReference RootDir in RootDirs) { // Find all the modules from the source folder DirectoryReference SourceDir = DirectoryReference.Combine(RootDir, "Source"); if (DirectoryReference.Exists(SourceDir)) { foreach (FileReference ModuleFile in DirectoryReference.EnumerateFiles(SourceDir, "*.Build.cs", SearchOption.AllDirectories)) { ModuleDirs.Add(ModuleFile.Directory); } } // Find all the modules under the plugins folder DirectoryReference PluginsDir = DirectoryReference.Combine(RootDir, "Plugins"); foreach (FileReference PluginFile in DirectoryReference.EnumerateFiles(PluginsDir, "*.uplugin", SearchOption.AllDirectories)) { DirectoryReference PluginSourceDir = DirectoryReference.Combine(PluginFile.Directory, "Source"); if (DirectoryReference.Exists(PluginSourceDir)) { foreach (FileReference PluginModuleFile in DirectoryReference.EnumerateFiles(PluginSourceDir, "*.Build.cs", SearchOption.AllDirectories)) { ModuleDirs.Add(PluginModuleFile.Directory); } } } } // Find a mapping from old to new include paths Dictionary <string, Tuple <string, FileReference> > RemapIncludePaths = new Dictionary <string, Tuple <string, FileReference> >(StringComparer.InvariantCultureIgnoreCase); foreach (DirectoryReference ModuleDir in ModuleDirs) { DirectoryReference ModulePublicDir = DirectoryReference.Combine(ModuleDir, "Public"); if (DirectoryReference.Exists(ModulePublicDir)) { foreach (FileReference HeaderFile in DirectoryReference.EnumerateFiles(ModulePublicDir, "*.h", SearchOption.AllDirectories)) { string BaseIncludeFile = HeaderFile.GetFileName(); Tuple <string, FileReference> ExistingIncludeName; if (RemapIncludePaths.TryGetValue(BaseIncludeFile, out ExistingIncludeName)) { LogWarning("Multiple include paths for {0}: {1}, {2}", BaseIncludeFile, ExistingIncludeName.Item2, HeaderFile); } else { RemapIncludePaths.Add(BaseIncludeFile, Tuple.Create(HeaderFile.MakeRelativeTo(ModulePublicDir).Replace('\\', '/'), HeaderFile)); } } } } // List of folders to exclude from updates FileSystemName[] ExcludeFoldersFromUpdate = { new FileSystemName("Intermediate"), new FileSystemName("ThirdParty") }; // Enumerate all the files to update HashSet <FileReference> UpdateFiles = new HashSet <FileReference>(); foreach (FileReference UpdateFile in DirectoryReference.EnumerateFiles(UpdateDir, "*", SearchOption.AllDirectories)) { if (!UpdateFile.ContainsAnyNames(ExcludeFoldersFromUpdate, UpdateDir)) { if (UpdateFile.HasExtension(".cpp") | UpdateFile.HasExtension(".h") || UpdateFile.HasExtension(".inl")) { UpdateFiles.Add(UpdateFile); } } } // Process all the source files Dictionary <FileReference, string[]> ModifiedFiles = new Dictionary <FileReference, string[]>(); foreach (FileReference UpdateFile in UpdateFiles) { bool bModifiedFile = false; string[] Lines = FileReference.ReadAllLines(UpdateFile); for (int Idx = 0; Idx < Lines.Length; Idx++) { Match Match = Regex.Match(Lines[Idx], "^(\\s*#\\s*include\\s+\\\")([^\"]+)(\\\".*)$"); if (Match.Success) { string IncludePath = Match.Groups[2].Value; Tuple <string, FileReference> NewIncludePath; if (RemapIncludePaths.TryGetValue(IncludePath, out NewIncludePath)) { if (IncludePath != NewIncludePath.Item1) { // Log("{0}: Changing {1} -> {2}", UpdateFile, IncludePath, NewIncludePath.Item1); Lines[Idx] = String.Format("{0}{1}{2}", Match.Groups[1].Value, NewIncludePath.Item1, Match.Groups[3].Value); bModifiedFile = true; } } } } if (bModifiedFile) { ModifiedFiles.Add(UpdateFile, Lines); } } // Output them all to disk if (bWrite && ModifiedFiles.Count > 0) { Log("Updating {0} files...", ModifiedFiles.Count); List <FileReference> FilesToCheckOut = new List <FileReference>(); foreach (FileReference ModifiedFile in ModifiedFiles.Keys) { if ((FileReference.GetAttributes(ModifiedFile) & FileAttributes.ReadOnly) != 0) { FilesToCheckOut.Add(ModifiedFile); } } if (FilesToCheckOut.Count > 0) { if (!P4Enabled) { throw new AutomationException("{0} files have been modified, but are read only. Run with -P4 to enable Perforce checkout.\n{1}", FilesToCheckOut.Count, String.Join("\n", FilesToCheckOut.Select(x => " " + x))); } Log("Checking out files from Perforce"); int ChangeNumber = P4.CreateChange(Description: "Updating source files"); P4.Edit(ChangeNumber, FilesToCheckOut.Select(x => x.FullName).ToList(), false); } foreach (KeyValuePair <FileReference, string[]> FileToWrite in ModifiedFiles) { Log("Writing {0}", FileToWrite.Key); FileReference.WriteAllLines(FileToWrite.Key, FileToWrite.Value); } } }
public override void ExecuteBuild() { var UEProjectRoot = ParseParamValue("UEProjectRoot"); if (UEProjectRoot == null) { UEProjectRoot = CmdEnv.LocalRoot; } var UEProjectDirectory = ParseParamValue("UEProjectDirectory"); if (UEProjectDirectory == null) { throw new AutomationException("Missing required command line argument: 'UEProjectDirectory'"); } var UEProjectName = ParseParamValue("UEProjectName"); if (UEProjectName == null) { UEProjectName = ""; } var LocalizationProjectNames = new List <string>(); { var LocalizationProjectNamesStr = ParseParamValue("LocalizationProjectNames"); if (LocalizationProjectNamesStr != null) { foreach (var ProjectName in LocalizationProjectNamesStr.Split(',')) { LocalizationProjectNames.Add(ProjectName.Trim()); } } } var LocalizationProviderName = ParseParamValue("LocalizationProvider"); if (LocalizationProviderName == null) { LocalizationProviderName = ""; } var LocalizationStepNames = new List <string>(); { var LocalizationStepNamesStr = ParseParamValue("LocalizationSteps"); if (LocalizationStepNamesStr == null) { LocalizationStepNames.AddRange(new string[] { "Download", "Gather", "Import", "Export", "Compile", "GenerateReports", "Upload" }); } else { foreach (var StepName in LocalizationStepNamesStr.Split(',')) { LocalizationStepNames.Add(StepName.Trim()); } } LocalizationStepNames.Add("Monolithic"); // Always allow the monolithic scripts to run as we don't know which steps they do } var ShouldGatherPlugins = ParseParam("IncludePlugins"); var IncludePlugins = new List <string>(); var ExcludePlugins = new List <string>(); if (ShouldGatherPlugins) { var IncludePluginsStr = ParseParamValue("IncludePlugins"); if (IncludePluginsStr != null) { foreach (var PluginName in IncludePluginsStr.Split(',')) { IncludePlugins.Add(PluginName.Trim()); } } var ExcludePluginsStr = ParseParamValue("ExcludePlugins"); if (ExcludePluginsStr != null) { foreach (var PluginName in ExcludePluginsStr.Split(',')) { ExcludePlugins.Add(PluginName.Trim()); } } } var ShouldGatherPlatforms = ParseParam("IncludePlatforms"); var AdditionalCommandletArguments = ParseParamValue("AdditionalCommandletArguments"); if (AdditionalCommandletArguments == null) { AdditionalCommandletArguments = ""; } var EnableParallelGather = ParseParam("ParallelGather"); var StartTime = DateTime.UtcNow; var LocalizationBatches = new List <LocalizationBatch>(); // Add the static set of localization projects as a batch if (LocalizationProjectNames.Count > 0) { LocalizationBatches.Add(new LocalizationBatch(UEProjectDirectory, UEProjectDirectory, "", LocalizationProjectNames)); } // Build up any additional batches needed for platforms if (ShouldGatherPlatforms) { var PlatformsRootDirectory = new DirectoryReference(CombinePaths(UEProjectRoot, UEProjectDirectory, "Platforms")); if (DirectoryReference.Exists(PlatformsRootDirectory)) { foreach (DirectoryReference PlatformDirectory in DirectoryReference.EnumerateDirectories(PlatformsRootDirectory)) { // Find the localization targets defined for this platform var PlatformTargetNames = GetLocalizationTargetsFromDirectory(new DirectoryReference(CombinePaths(PlatformDirectory.FullName, "Config", "Localization"))); if (PlatformTargetNames.Count > 0) { var RootRelativePluginPath = PlatformDirectory.MakeRelativeTo(new DirectoryReference(UEProjectRoot)); RootRelativePluginPath = RootRelativePluginPath.Replace('\\', '/'); // Make sure we use / as these paths are used with P4 LocalizationBatches.Add(new LocalizationBatch(UEProjectDirectory, RootRelativePluginPath, "", PlatformTargetNames)); } } } } // Build up any additional batches needed for plugins if (ShouldGatherPlugins) { var PluginsRootDirectory = new DirectoryReference(CombinePaths(UEProjectRoot, UEProjectDirectory)); IReadOnlyList <PluginInfo> AllPlugins = Plugins.ReadPluginsFromDirectory(PluginsRootDirectory, "Plugins", UEProjectName.Length == 0 ? PluginType.Engine : PluginType.Project); // Add a batch for each plugin that meets our criteria var AvailablePluginNames = new HashSet <string>(); foreach (var PluginInfo in AllPlugins) { AvailablePluginNames.Add(PluginInfo.Name); bool ShouldIncludePlugin = (IncludePlugins.Count == 0 || IncludePlugins.Contains(PluginInfo.Name)) && !ExcludePlugins.Contains(PluginInfo.Name); if (ShouldIncludePlugin && PluginInfo.Descriptor.LocalizationTargets != null && PluginInfo.Descriptor.LocalizationTargets.Length > 0) { var RootRelativePluginPath = PluginInfo.Directory.MakeRelativeTo(new DirectoryReference(UEProjectRoot)); RootRelativePluginPath = RootRelativePluginPath.Replace('\\', '/'); // Make sure we use / as these paths are used with P4 var PluginTargetNames = new List <string>(); foreach (var LocalizationTarget in PluginInfo.Descriptor.LocalizationTargets) { PluginTargetNames.Add(LocalizationTarget.Name); } LocalizationBatches.Add(new LocalizationBatch(UEProjectDirectory, RootRelativePluginPath, PluginInfo.Name, PluginTargetNames)); } } // If we had an explicit list of plugins to include, warn if any were missing foreach (string PluginName in IncludePlugins) { if (!AvailablePluginNames.Contains(PluginName)) { LogWarning("The plugin '{0}' specified by -IncludePlugins wasn't found and will be skipped.", PluginName); } } } // Create a single changelist to use for all changes int PendingChangeList = 0; if (P4Enabled) { var ChangeListCommitMessage = String.Format("Localization Automation using CL {0}", P4Env.Changelist); if (File.Exists(CombinePaths(CmdEnv.LocalRoot, @"Engine/Build/NotForLicensees/EpicInternal.txt"))) { ChangeListCommitMessage += "\n#okforgithub ignore"; } PendingChangeList = P4.CreateChange(P4Env.Client, ChangeListCommitMessage); } // Prepare to process each localization batch var LocalizationTasks = new List <LocalizationTask>(); foreach (var LocalizationBatch in LocalizationBatches) { var LocalizationTask = new LocalizationTask(LocalizationBatch, UEProjectRoot, LocalizationProviderName, PendingChangeList, this); LocalizationTasks.Add(LocalizationTask); // Make sure the Localization configs and content is up-to-date to ensure we don't get errors later on if (P4Enabled) { LogInformation("Sync necessary content to head revision"); P4.Sync(P4Env.Branch + "/" + LocalizationTask.Batch.LocalizationTargetDirectory + "/Config/Localization/..."); P4.Sync(P4Env.Branch + "/" + LocalizationTask.Batch.LocalizationTargetDirectory + "/Content/Localization/..."); } // Generate the info we need to gather for each project foreach (var ProjectName in LocalizationTask.Batch.LocalizationProjectNames) { LocalizationTask.ProjectInfos.Add(GenerateProjectInfo(LocalizationTask.RootLocalizationTargetDirectory, ProjectName, LocalizationStepNames)); } } // Hash the current PO files on disk so we can work out whether they actually change Dictionary <string, byte[]> InitalPOFileHashes = null; if (P4Enabled) { InitalPOFileHashes = GetPOFileHashes(LocalizationBatches, UEProjectRoot); } // Download the latest translations from our localization provider if (LocalizationStepNames.Contains("Download")) { foreach (var LocalizationTask in LocalizationTasks) { if (LocalizationTask.LocProvider != null) { foreach (var ProjectInfo in LocalizationTask.ProjectInfos) { LocalizationTask.LocProvider.DownloadProjectFromLocalizationProvider(ProjectInfo.ProjectName, ProjectInfo.ImportInfo); } } } } // Begin the gather command for each task // These can run in parallel when ParallelGather is enabled { var EditorExe = CombinePaths(CmdEnv.LocalRoot, @"Engine/Binaries/Win64/UE4Editor-Cmd.exe"); // Set the common basic editor arguments var EditorArguments = P4Enabled ? String.Format("-SCCProvider=Perforce -P4Port={0} -P4User={1} -P4Client={2} -P4Passwd={3} -P4Changelist={4} -EnableSCC -DisableSCCSubmit", P4Env.ServerAndPort, P4Env.User, P4Env.Client, P4.GetAuthenticationToken(), PendingChangeList) : "-SCCProvider=None"; if (IsBuildMachine) { EditorArguments += " -BuildMachine"; } EditorArguments += " -Unattended -LogLocalizationConflicts"; if (EnableParallelGather) { EditorArguments += " -multiprocess"; } if (!String.IsNullOrEmpty(AdditionalCommandletArguments)) { EditorArguments += " " + AdditionalCommandletArguments; } // Set the common process run options var CommandletRunOptions = ERunOptions.Default | ERunOptions.NoLoggingOfRunCommand; // Disable logging of the run command as it will print the exit code which GUBP can pick up as an error (we do that ourselves later) if (EnableParallelGather) { CommandletRunOptions |= ERunOptions.NoWaitForExit; } foreach (var LocalizationTask in LocalizationTasks) { var ProjectArgument = String.IsNullOrEmpty(UEProjectName) ? "" : String.Format("\"{0}\"", Path.Combine(LocalizationTask.RootWorkingDirectory, String.Format("{0}.uproject", UEProjectName))); foreach (var ProjectInfo in LocalizationTask.ProjectInfos) { var LocalizationConfigFiles = new List <string>(); foreach (var LocalizationStep in ProjectInfo.LocalizationSteps) { if (LocalizationStepNames.Contains(LocalizationStep.Name)) { LocalizationConfigFiles.Add(LocalizationStep.LocalizationConfigFile); } } if (LocalizationConfigFiles.Count > 0) { var Arguments = String.Format("{0} -run=GatherText -config=\"{1}\" {2}", ProjectArgument, String.Join(";", LocalizationConfigFiles), EditorArguments); LogInformation("Running localization commandlet for '{0}': {1}", ProjectInfo.ProjectName, Arguments); LocalizationTask.GatherProcessResults.Add(Run(EditorExe, Arguments, null, CommandletRunOptions)); } else { LocalizationTask.GatherProcessResults.Add(null); } } } } // Wait for each commandlet process to finish and report the result. // This runs even for non-parallel execution to log the exit state of the process. foreach (var LocalizationTask in LocalizationTasks) { for (int ProjectIndex = 0; ProjectIndex < LocalizationTask.ProjectInfos.Count; ++ProjectIndex) { var ProjectInfo = LocalizationTask.ProjectInfos[ProjectIndex]; var RunResult = LocalizationTask.GatherProcessResults[ProjectIndex]; if (RunResult != null) { RunResult.WaitForExit(); RunResult.OnProcessExited(); RunResult.DisposeProcess(); if (RunResult.ExitCode == 0) { LogInformation("The localization commandlet for '{0}' exited with code 0.", ProjectInfo.ProjectName); } else { LogWarning("The localization commandlet for '{0}' exited with code {1} which likely indicates a crash.", ProjectInfo.ProjectName, RunResult.ExitCode); } } } } // Upload the latest sources to our localization provider if (LocalizationStepNames.Contains("Upload")) { foreach (var LocalizationTask in LocalizationTasks) { if (LocalizationTask.LocProvider != null) { // Upload all text to our localization provider for (int ProjectIndex = 0; ProjectIndex < LocalizationTask.ProjectInfos.Count; ++ProjectIndex) { var ProjectInfo = LocalizationTask.ProjectInfos[ProjectIndex]; var RunResult = LocalizationTask.GatherProcessResults[ProjectIndex]; if (RunResult != null && RunResult.ExitCode == 0) { // Recalculate the split platform paths before doing the upload, as the export may have changed them ProjectInfo.ExportInfo.CalculateSplitPlatformNames(LocalizationTask.RootLocalizationTargetDirectory); LocalizationTask.LocProvider.UploadProjectToLocalizationProvider(ProjectInfo.ProjectName, ProjectInfo.ExportInfo); } else { LogWarning("Skipping upload to the localization provider for '{0}' due to an earlier commandlet failure.", ProjectInfo.ProjectName); } } } } } // Clean-up the changelist so it only contains the changed files, and then submit it (if we were asked to) if (P4Enabled) { // Revert any PO files that haven't changed aside from their header { var POFilesToRevert = new List <string>(); var CurrentPOFileHashes = GetPOFileHashes(LocalizationBatches, UEProjectRoot); foreach (var CurrentPOFileHashPair in CurrentPOFileHashes) { byte[] InitialPOFileHash; if (InitalPOFileHashes.TryGetValue(CurrentPOFileHashPair.Key, out InitialPOFileHash) && InitialPOFileHash.SequenceEqual(CurrentPOFileHashPair.Value)) { POFilesToRevert.Add(CurrentPOFileHashPair.Key); } } if (POFilesToRevert.Count > 0) { var P4RevertArgsFilename = CombinePaths(CmdEnv.LocalRoot, "Engine", "Intermediate", String.Format("LocalizationP4RevertArgs-{0}.txt", Guid.NewGuid().ToString())); using (StreamWriter P4RevertArgsWriter = File.CreateText(P4RevertArgsFilename)) { foreach (var POFileToRevert in POFilesToRevert) { P4RevertArgsWriter.WriteLine(POFileToRevert); } } P4.LogP4(String.Format("-x{0} revert", P4RevertArgsFilename)); DeleteFile_NoExceptions(P4RevertArgsFilename); } } // Revert any other unchanged files P4.RevertUnchanged(PendingChangeList); // Submit that single changelist now if (AllowSubmit) { int SubmittedChangeList; P4.Submit(PendingChangeList, out SubmittedChangeList); } } var RunDuration = (DateTime.UtcNow - StartTime).TotalMilliseconds; LogInformation("Localize command finished in {0} seconds", RunDuration / 1000); }
private static bool RequiresTempTarget(FileReference RawProjectPath, List <UnrealTargetPlatform> 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 <UnrealTargetPlatform> TargetPlatforms = ClientTargetPlatforms; if (ClientTargetPlatforms == null || ClientTargetPlatforms.Count < 1) { // No client target platforms, add all in TargetPlatforms = new List <UnrealTargetPlatform>(); 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 <PluginInfo> 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 FindAndCompileScriptModules(string ScriptsForProjectFileName, List <string> AdditionalScriptsFolders) { Log.TraceInformation("Compiling scripts."); var OldCWD = Environment.CurrentDirectory; var UnrealBuildToolCWD = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine", "Source"); Environment.CurrentDirectory = UnrealBuildToolCWD; // Configure the rules compiler // Get all game folders and convert them to build subfolders. List <DirectoryReference> AllGameFolders; if (ScriptsForProjectFileName == null) { AllGameFolders = UProjectInfo.AllProjectFiles.Select(x => x.Directory).ToList(); } else { AllGameFolders = new List <DirectoryReference> { new DirectoryReference(Path.GetDirectoryName(ScriptsForProjectFileName)) }; } var AllAdditionalScriptFolders = new List <DirectoryReference>(AdditionalScriptsFolders.Select(x => new DirectoryReference(x))); foreach (var Folder in AllGameFolders) { var GameBuildFolder = DirectoryReference.Combine(Folder, "Build"); if (DirectoryReference.Exists(GameBuildFolder)) { AllAdditionalScriptFolders.Add(GameBuildFolder); } } Log.TraceVerbose("Discovering game folders."); var DiscoveredModules = UnrealBuildTool.RulesCompiler.FindAllRulesSourceFiles(UnrealBuildTool.RulesCompiler.RulesFileType.AutomationModule, GameFolders: AllGameFolders, ForeignPlugins: null, AdditionalSearchPaths: AllAdditionalScriptFolders); var ModulesToCompile = new List <string>(DiscoveredModules.Count); foreach (var ModuleFilename in DiscoveredModules) { if (HostPlatform.Current.IsScriptModuleSupported(ModuleFilename.GetFileNameWithoutAnyExtensions())) { ModulesToCompile.Add(ModuleFilename.FullName); } else { CommandUtils.LogVerbose("Script module {0} filtered by the Host Platform and will not be compiled.", ModuleFilename); } } if ((UnrealBuildTool.BuildHostPlatform.Current.Platform == UnrealBuildTool.UnrealTargetPlatform.Win64) || (UnrealBuildTool.BuildHostPlatform.Current.Platform == UnrealBuildTool.UnrealTargetPlatform.Win32)) { string Modules = string.Join(";", ModulesToCompile.ToArray()); var UATProj = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, @"Engine\Source\Programs\AutomationTool\Scripts\UAT.proj"); var CmdLine = String.Format("\"{0}\" /p:Modules=\"{1}\" /p:Configuration={2} /verbosity:minimal /nologo", UATProj, Modules, BuildConfig); // suppress the run command because it can be long and intimidating, making the logs around this code harder to read. var Result = CommandUtils.Run(CommandUtils.CmdEnv.MsBuildExe, CmdLine, Options: CommandUtils.ERunOptions.Default | CommandUtils.ERunOptions.NoLoggingOfRunCommand | CommandUtils.ERunOptions.LoggingOfRunDuration); if (Result.ExitCode != 0) { throw new AutomationException(String.Format("Failed to build \"{0}\":{1}{2}", UATProj, Environment.NewLine, Result.Output)); } } else { CompileModules(ModulesToCompile); } Environment.CurrentDirectory = OldCWD; }
/// <summary> /// Find paths to all the plugins under a given parent directory (recursively) /// </summary> /// <param name="ParentDirectory">Parent directory to look in. Plugins will be found in any *subfolders* of this directory.</param> public static IEnumerable<FileReference> EnumeratePlugins(DirectoryReference ParentDirectory) { List<FileReference> FileNames; if (!PluginFileCache.TryGetValue(ParentDirectory, out FileNames)) { FileNames = new List<FileReference>(); if (ParentDirectory.Exists()) { EnumeratePluginsInternal(ParentDirectory, FileNames); } PluginFileCache.Add(ParentDirectory, FileNames); } return FileNames; }
private static void FindOutputFilesHelper(HashSet<FileReference> OutputFiles, DirectoryReference BaseDir, string SearchPrefix, PhysXTargetLib TargetLib) { if(!BaseDir.Exists()) { return; } foreach (FileReference FoundFile in BaseDir.EnumerateFileReferences(SearchPrefix)) { string FileNameUpper = FoundFile.GetFileName().ToString().ToUpper(); bool bIncludeFile = false; if(TargetLib == PhysXTargetLib.APEX) { bIncludeFile = FileGeneratedByAPEX(FileNameUpper); } else { bIncludeFile = !FileGeneratedByAPEX(FileNameUpper); } if(bIncludeFile) { OutputFiles.Add(FoundFile); } } }
/// <summary> /// Execute the task. /// </summary> /// <param name="Job">Information about the current job</param> /// <param name="BuildProducts">Set of build products produced by this node.</param> /// <param name="TagNameToFileSet">Mapping from tag names to the set of files they include</param> public override void Execute(JobContext Job, HashSet <FileReference> BuildProducts, Dictionary <string, HashSet <FileReference> > TagNameToFileSet) { // Parse all the source patterns FilePattern SourcePattern = new FilePattern(CommandUtils.RootDirectory, Parameters.From); // Parse the target pattern FilePattern TargetPattern = new FilePattern(CommandUtils.RootDirectory, Parameters.To); // Apply the filter to the source files HashSet <FileReference> Files = null; if (!String.IsNullOrEmpty(Parameters.Files)) { SourcePattern = SourcePattern.AsDirectoryPattern(); Files = ResolveFilespec(SourcePattern.BaseDirectory, Parameters.Files, TagNameToFileSet); } // Build the file mapping Dictionary <FileReference, FileReference> TargetFileToSourceFile = FilePattern.CreateMapping(Files, ref SourcePattern, ref TargetPattern); // If we're not overwriting, remove any files where the destination file already exists. if (!Parameters.Overwrite) { TargetFileToSourceFile = TargetFileToSourceFile.Where(File => { if (FileReference.Exists(File.Key)) { CommandUtils.LogInformation("Not copying existing file {0}", File.Key); return(false); } return(true); }).ToDictionary(Pair => Pair.Key, Pair => Pair.Value); } // Check we got some files if (TargetFileToSourceFile.Count == 0) { CommandUtils.LogInformation("No files found matching '{0}'", SourcePattern); return; } // If the target is on a network share, retry creating the first directory until it succeeds DirectoryReference FirstTargetDirectory = TargetFileToSourceFile.First().Key.Directory; if (!DirectoryReference.Exists(FirstTargetDirectory)) { const int MaxNumRetries = 15; for (int NumRetries = 0;; NumRetries++) { try { DirectoryReference.CreateDirectory(FirstTargetDirectory); if (NumRetries == 1) { Log.TraceInformation("Created target directory {0} after 1 retry.", FirstTargetDirectory); } else if (NumRetries > 1) { Log.TraceInformation("Created target directory {0} after {1} retries.", FirstTargetDirectory, NumRetries); } break; } catch (Exception Ex) { if (NumRetries == 0) { Log.TraceInformation("Unable to create directory '{0}' on first attempt. Retrying {1} times...", FirstTargetDirectory, MaxNumRetries); } Log.TraceLog(" {0}", Ex); if (NumRetries >= 15) { throw new AutomationException(Ex, "Unable to create target directory '{0}' after {1} retries.", FirstTargetDirectory, NumRetries); } Thread.Sleep(2000); } } } // Copy them all KeyValuePair <FileReference, FileReference>[] FilePairs = TargetFileToSourceFile.ToArray(); CommandUtils.LogInformation("Copying {0} file{1} from {2} to {3}...", FilePairs.Length, (FilePairs.Length == 1)? "" : "s", SourcePattern.BaseDirectory, TargetPattern.BaseDirectory); foreach (KeyValuePair <FileReference, FileReference> FilePair in FilePairs) { CommandUtils.LogLog(" {0} -> {1}", FilePair.Value, FilePair.Key); } CommandUtils.ThreadedCopyFiles(FilePairs.Select(x => x.Value.FullName).ToList(), FilePairs.Select(x => x.Key.FullName).ToList(), bQuiet: true); // Update the list of build products BuildProducts.UnionWith(TargetFileToSourceFile.Keys); // Apply the optional output tag to them foreach (string TagName in FindTagNamesFromList(Parameters.Tag)) { FindOrAddTagSet(TagNameToFileSet, TagName).UnionWith(TargetFileToSourceFile.Keys); } }
public override void CleanProjectFiles(DirectoryReference InMasterProjectDirectory, string InMasterProjectName, DirectoryReference InIntermediateProjectFilesDirectory) { // TODO Delete all files here. Not finished yet. var SolutionFileName = InMasterProjectName + SolutionExtension; var CodeCompletionFile = InMasterProjectName + CodeCompletionFileName; var CodeCompletionPreProcessorFile = InMasterProjectName + CodeCompletionPreProcessorFileName; FileReference FullCodeLiteMasterFile = FileReference.Combine(InMasterProjectDirectory, SolutionFileName); FileReference FullCodeLiteCodeCompletionFile = FileReference.Combine(InMasterProjectDirectory, CodeCompletionFile); FileReference FullCodeLiteCodeCompletionPreProcessorFile = FileReference.Combine(InMasterProjectDirectory, CodeCompletionPreProcessorFile); if (FullCodeLiteMasterFile.Exists()) { FullCodeLiteMasterFile.Delete(); } if (FullCodeLiteCodeCompletionFile.Exists()) { FullCodeLiteCodeCompletionFile.Delete(); } if (FullCodeLiteCodeCompletionPreProcessorFile.Exists()) { FullCodeLiteCodeCompletionPreProcessorFile.Delete(); } // Delete the project files folder if (InIntermediateProjectFilesDirectory.Exists()) { try { Directory.Delete(InIntermediateProjectFilesDirectory.FullName, true); } catch (Exception Ex) { Log.TraceInformation("Error while trying to clean project files path {0}. Ignored.", InIntermediateProjectFilesDirectory); Log.TraceInformation("\t" + Ex.Message); } } }