private static void FindAndCompileScriptModules(string ScriptsForProjectFileName, List <string> AdditionalScriptsFolders) { 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 = NativeProjects.EnumerateProjectFiles().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); } } CompileModules(ModulesToCompile); Environment.CurrentDirectory = OldCWD; }
private static List <FileReference> FindAutomationProjects(string ScriptsForProjectFileName, List <string> AdditionalScriptsFolders) { // Configure the rules compiler // Get all game folders and convert them to build subfolders. List <DirectoryReference> AllGameFolders = new List <DirectoryReference>(); if (ScriptsForProjectFileName == null) { AllGameFolders = NativeProjects.EnumerateProjectFiles().Select(x => x.Directory).ToList(); } else { // Project automation scripts currently require source engine builds if (!CommandUtils.IsEngineInstalled()) { AllGameFolders = new List <DirectoryReference> { new DirectoryReference(Path.GetDirectoryName(ScriptsForProjectFileName)) }; } } List <DirectoryReference> AllAdditionalScriptFolders = AdditionalScriptsFolders.Select(x => new DirectoryReference(x)).ToList(); foreach (DirectoryReference Folder in AllGameFolders) { DirectoryReference GameBuildFolder = DirectoryReference.Combine(Folder, "Build"); if (DirectoryReference.Exists(GameBuildFolder)) { AllAdditionalScriptFolders.Add(GameBuildFolder); } } Log.TraceVerbose("Discovering game folders."); List <FileReference> DiscoveredModules = UnrealBuildTool.RulesCompiler.FindAllRulesSourceFiles(UnrealBuildTool.RulesCompiler.RulesFileType.AutomationModule, GameFolders: AllGameFolders, ForeignPlugins: null, AdditionalSearchPaths: AllAdditionalScriptFolders); List <FileReference> ModulesToCompile = new List <FileReference>(DiscoveredModules.Count); foreach (FileReference ModuleFilename in DiscoveredModules) { if (HostPlatform.Current.IsScriptModuleSupported(ModuleFilename.GetFileNameWithoutAnyExtensions())) { ModulesToCompile.Add(ModuleFilename); } else { CommandUtils.LogVerbose("Script module {0} filtered by the Host Platform and will not be compiled.", ModuleFilename); } } return(ModulesToCompile); }
/// <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) { // Get the full path to the project file FileReference ProjectFile = null; if (!String.IsNullOrEmpty(Parameters.Project)) { if (Parameters.Project.EndsWith(".uproject", StringComparison.OrdinalIgnoreCase)) { ProjectFile = ResolveFile(Parameters.Project); } else { ProjectFile = NativeProjects.EnumerateProjectFiles().FirstOrDefault(x => x.GetFileNameWithoutExtension().Equals(Parameters.Project, StringComparison.OrdinalIgnoreCase)); } if (ProjectFile == null || !FileReference.Exists(ProjectFile)) { throw new BuildException("Unable to resolve project '{0}'", Parameters.Project); } } // Get the path to the editor, and check it exists FileReference EditorExe; if (Parameters.EditorExe == null) { EditorExe = new FileReference(HostPlatform.Current.GetUE4ExePath("UE4Editor-Cmd.exe")); } else { EditorExe = Parameters.EditorExe; } // Make sure the editor exists if (!FileReference.Exists(EditorExe)) { throw new AutomationException("{0} does not exist", EditorExe.FullName); } // Run the commandlet CommandUtils.RunCommandlet(ProjectFile, EditorExe.FullName, Parameters.Name, Parameters.Arguments, Parameters.ErrorLevel); }
/// <summary> /// Takes a game name (e.g "ShooterGame") and tries to find the path to the project file /// </summary> /// <param name="GameName"></param> /// <returns></returns> public static FileReference FindProjectFileFromName(string GameName) { // if they passed in a path then easy. if (File.Exists(GameName)) { return(new FileReference(GameName)); } // Start with the gamename regardless of what they passed in GameName = Path.GetFileNameWithoutExtension(GameName); // Turn Foo into Foo.uproject string ProjectFile = GameName; if (string.IsNullOrEmpty(Path.GetExtension(ProjectFile))) { // if project was specified but had no extension then just add it. ProjectFile = Path.ChangeExtension(GameName, ".uproject"); } // Turn Foo.uproject into Foo/Foo.uproject ProjectFile = Path.Combine(GameName, ProjectFile); GameName = Path.GetFileNameWithoutExtension(GameName); // check for sibling to engine if (File.Exists(ProjectFile)) { return(new FileReference(ProjectFile)); } // Search NativeProjects (sibling folders). IEnumerable <FileReference> Projects = NativeProjects.EnumerateProjectFiles(); FileReference ProjectPath = Projects.Where(R => string.Equals(R.GetFileName(), ProjectFile, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); if (ProjectPath == null) { // read .uprojectdirs List <string> SearchPaths = new List <string>(); SearchPaths.Add(""); string ProjectDirsFile = Directory.EnumerateFiles(Environment.CurrentDirectory, "*.uprojectdirs").FirstOrDefault(); if (ProjectDirsFile != null) { foreach (string FilePath in File.ReadAllLines(ProjectDirsFile)) { string Trimmed = FilePath.Trim(); if (!Trimmed.StartsWith("./", StringComparison.OrdinalIgnoreCase) && !Trimmed.StartsWith(";", StringComparison.OrdinalIgnoreCase) && Trimmed.IndexOfAny(Path.GetInvalidPathChars()) < 0) { SearchPaths.Add(Trimmed); } } string ResolvedFile = SearchPaths.Select(P => Path.Combine(P, ProjectFile)) .Where(P => File.Exists(P)) .FirstOrDefault(); if (ResolvedFile != null) { ProjectPath = new FileReference(ResolvedFile); } } } // either valid or we're out of ideas... return(ProjectPath); }
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 = NativeProjects.EnumerateProjectFiles().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; }
public override ExitCode Execute() { LogInformation("************************* SyncProject"); // These are files that should always be synced because tools update them string[] ForceSyncFiles = new string[] { "Engine/Build/Build.version", "Engine/Source/Programs/DotNETCommon/MetaData.cs" }; // Parse the project filename (as a local path) string ProjectArg = ParseParamValue("Project", null); // Parse the changelist to sync to. -1 will sync to head. int CL = ParseParamInt("CL", -1); int Threads = ParseParamInt("threads", 2); bool ForceSync = ParseParam("force"); bool PreviewOnly = ParseParam("preview"); bool ProjectOnly = ParseParam("projectonly"); int Retries = ParseParamInt("retries", 3); bool Unversioned = ParseParam("unversioned"); bool BuildProject = ParseParam("build"); bool OpenProject = ParseParam("open"); bool GenerateProject = ParseParam("generate"); string PathArg = ParseParamValue("paths", ""); IEnumerable <string> ExplicitPaths = PathArg.Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries).Select(S => S.Trim()); if (CL == 0) { if (!ForceSync) { throw new AutomationException("If using 0 CL to remove files -force must also be specified"); } // Cannot unsync the engine folder ProjectOnly = true; } else if (CL == -1) { // find most recent change List <P4Connection.ChangeRecord> Records; string Cmd = string.Format("-s submitted -m1 //{0}/...", P4Env.Client); if (!P4.Changes(out Records, Cmd, false)) { throw new AutomationException("p4 changes failed. Cannot find most recent CL"); } CL = Records.First().CL; } bool EngineOnly = string.IsNullOrEmpty(ProjectArg); // Will be the full local path to the project file once resolved FileReference ProjectFile = null; // Will be the full workspace path to the project in P4 (if a project was specified) string P4ProjectPath = null; // Will be the full workspace path to the engine in P4 (If projectonly wasn't specified); string P4EnginePath = null; // If we're syncing a project find where it is in P4 if (!EngineOnly) { ProjectFile = ProjectUtils.FindProjectFileFromName(ProjectArg); if (ProjectFile != null) { // get the path in P4 P4WhereRecord Record = P4.Where(ProjectFile.FullName, AllowSpew: false).FirstOrDefault(x => x.DepotFile != null && !x.bUnmap); P4ProjectPath = Record.ClientFile; } else { // if they provided a name and not a path then find the file (requires that it's synced). string RelativePath = ProjectArg; if (Path.GetExtension(RelativePath).Length == 0) { RelativePath = Path.ChangeExtension(RelativePath, "uproject"); } if (!RelativePath.Contains(Path.DirectorySeparatorChar) && !RelativePath.Contains(Path.AltDirectorySeparatorChar)) { RelativePath = CommandUtils.CombinePaths(PathSeparator.Slash, Path.GetFileNameWithoutExtension(RelativePath), RelativePath); } Log.TraceInformation("{0} not on disk. Searching P4 for {1}", ProjectArg, RelativePath); List <string> SearchPaths = new List <string>(); SearchPaths.Add(""); string ProjectDirsFile = Directory.EnumerateFiles(CommandUtils.CombinePaths(CmdEnv.LocalRoot), "*.uprojectdirs").FirstOrDefault(); if (ProjectDirsFile != null) { foreach (string FilePath in File.ReadAllLines(ProjectDirsFile)) { string Trimmed = FilePath.Trim(); if (!Trimmed.StartsWith("./", StringComparison.OrdinalIgnoreCase) && !Trimmed.StartsWith(";", StringComparison.OrdinalIgnoreCase) && Trimmed.IndexOfAny(Path.GetInvalidPathChars()) < 0) { SearchPaths.Add(Trimmed); } } } // Get the root of the branch containing the selected file foreach (string SearchPath in SearchPaths) { string P4Path = CommandUtils.CombinePaths(PathSeparator.Slash, P4Env.ClientRoot, SearchPath, RelativePath); if (P4.FileExistsInDepot(P4Path)) { P4WhereRecord Record = P4.Where(P4Path, AllowSpew: false).FirstOrDefault(x => x.DepotFile != null && !x.bUnmap); // make sure to sync with //workspace/path as it cleans up files if the user has stream switched P4ProjectPath = Record.ClientFile; Log.TraceInformation("Found project at {0}", P4ProjectPath); break; } } } if (string.IsNullOrEmpty(P4ProjectPath)) { throw new AutomationException("Could not find project file for {0} locally or in P4. Provide a full path or check the subdirectory is listed in UE4Games.uprojectdirs", ProjectArg); } Log.TraceVerbose("Resolved {0} to P4 Path {1}", ProjectArg, P4ProjectPath); } // Build the list of paths that need syncing List <string> SyncPaths = new List <string>(); // if (ExplicitPaths.Any()) { // Add all explicit paths as <root>/Path/... ExplicitPaths.ToList().ForEach(P => SyncPaths.Add(CommandUtils.CombinePaths(PathSeparator.Slash, P4Env.ClientRoot, P, "..."))); } else { // See if the engine is in P4 too by checking the p4 location of a local file string LocalEngineFile = CommandUtils.CombinePaths(CmdEnv.LocalRoot, "Engine", "Source", "UE4Editor.target.cs"); P4WhereRecord EngineRecord = P4.Where(LocalEngineFile, AllowSpew: false).FirstOrDefault(x => x.DepotFile != null && !x.bUnmap); if (!ProjectOnly && P4.FileExistsInDepot(EngineRecord.DepotFile)) { // make sure to sync with //workspace/path as it cleans up files if the user has stream switched P4EnginePath = EngineRecord.ClientFile.Replace("Engine/Source/UE4Editor.target.cs", ""); SyncPaths.Add(CommandUtils.CombinePaths(PathSeparator.Slash, P4EnginePath + "*")); SyncPaths.Add(CommandUtils.CombinePaths(PathSeparator.Slash, P4EnginePath, "Engine", "...")); } if (!string.IsNullOrEmpty(P4ProjectPath)) { string P4ProjectDir = Regex.Replace(P4ProjectPath, @"[^/]+\.uproject", "...", RegexOptions.IgnoreCase); SyncPaths.Add(P4ProjectDir); } } // Force these files as they can be overwritten by tools if (!PreviewOnly && !string.IsNullOrEmpty(P4EnginePath) && !ProjectOnly) { IEnumerable <string> ForceSyncList = ForceSyncFiles.Select(F => CommandUtils.CombinePaths(PathSeparator.Slash, P4EnginePath, F)); foreach (var F in ForceSyncList) { LogInformation("Force-updating {0}", F); string SyncCommand = string.Format("-f {0}@{1}", F, CL); // sync with retries P4.Sync(SyncCommand, true, false, Retries); } } // Sync all the things foreach (string SyncPath in SyncPaths) { string SyncCommand = ""; if (Threads > 1) { SyncCommand = string.Format(" --parallel \"threads={0}\" {1}", Threads, SyncCommand); } if (ForceSync) { SyncCommand = SyncCommand + " -f"; } SyncCommand += string.Format(" {0}@{1}", SyncPath, CL); if (!PreviewOnly) { // sync with retries P4.Sync(SyncCommand, true, false, Retries); } else { LogInformation("sync {0}", SyncCommand); } } // P4 utils don't return errors :( ExitCode ExitStatus = ExitCode.Success; // Sync is complete so do the actions if (!PreviewOnly && CL > 0) { // Argument to pass to the editor (could be null with no project). string ProjectArgForEditor = ""; if (!string.IsNullOrEmpty(ProjectArg)) { // If we synced the project from P4 we couldn't resolve this earlier if (ProjectFile == null) { NativeProjects.ClearCache(); ProjectFile = ProjectUtils.FindProjectFileFromName(ProjectArg); } ProjectArgForEditor = ProjectFile.FullName; } if (GenerateProject) { Log.TraceVerbose("Generating project files for {0}", ProjectArgForEditor); if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win64 || BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win32) { CommandUtils.Run("GenerateProjectFiles.bat", ProjectArgForEditor); } else { CommandUtils.Run("GenerateProjectFiles.sh", ProjectArgForEditor); } } UE4Build Build = new UE4Build(this); if (!Unversioned && !ProjectOnly) { Build.UpdateVersionFiles(ActuallyUpdateVersionFiles: true, ChangelistNumberOverride: CL, IsPromotedOverride: false); } // Build everything if (BuildProject && ExitStatus == ExitCode.Success) { Log.TraceVerbose("Building Editor for {0}", ProjectArgForEditor); BuildEditor BuildCmd = new BuildEditor(); BuildCmd.Clean = ParseParam("clean"); BuildCmd.ProjectName = ProjectArgForEditor; ExitStatus = BuildCmd.Execute(); } if (OpenProject && ExitStatus == ExitCode.Success) { Log.TraceVerbose("Opening Editor for {0}", ProjectArgForEditor); OpenEditor OpenCmd = new OpenEditor(); OpenCmd.ProjectName = ProjectArgForEditor; ExitStatus = OpenCmd.Execute(); } } return(ExitCode.Success); }