示例#1
0
        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);
        }
示例#4
0
        /// <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);
        }
示例#5
0
        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);
    }