public LocalizationTask(LocalizationBatch InBatch, string InUEProjectRoot, string InLocalizationProviderName, int InPendingChangeList, BuildCommand InCommand)
        {
            Batch = InBatch;
            RootWorkingDirectory            = CombinePaths(InUEProjectRoot, Batch.UEProjectDirectory);
            RootLocalizationTargetDirectory = CombinePaths(InUEProjectRoot, Batch.LocalizationTargetDirectory);

            // Try and find our localization provider
            {
                LocalizationProvider.LocalizationProviderArgs LocProviderArgs;
                LocProviderArgs.RootWorkingDirectory            = RootWorkingDirectory;
                LocProviderArgs.RootLocalizationTargetDirectory = RootLocalizationTargetDirectory;
                LocProviderArgs.RemoteFilenamePrefix            = Batch.RemoteFilenamePrefix;
                LocProviderArgs.Command           = InCommand;
                LocProviderArgs.PendingChangeList = InPendingChangeList;
                LocProvider = LocalizationProvider.GetLocalizationProvider(InLocalizationProviderName, LocProviderArgs);
            }
        }
    private void ProcessLocalizationProjects(LocalizationBatch LocalizationBatch, int PendingChangeList, string UEProjectRoot, string UEProjectName, string LocalizationProviderName, List <string> LocalizationSteps, string AdditionalCommandletArguments)
    {
        var EditorExe                       = CombinePaths(CmdEnv.LocalRoot, @"Engine/Binaries/Win64/UE4Editor-Cmd.exe");
        var RootWorkingDirectory            = CombinePaths(UEProjectRoot, LocalizationBatch.UEProjectDirectory);
        var RootLocalizationTargetDirectory = CombinePaths(UEProjectRoot, LocalizationBatch.LocalizationTargetDirectory);

        // Try and find our localization provider
        LocalizationProvider LocProvider = null;

        {
            LocalizationProvider.LocalizationProviderArgs LocProviderArgs;
            LocProviderArgs.RootWorkingDirectory            = RootWorkingDirectory;
            LocProviderArgs.RootLocalizationTargetDirectory = RootLocalizationTargetDirectory;
            LocProviderArgs.RemoteFilenamePrefix            = LocalizationBatch.RemoteFilenamePrefix;
            LocProviderArgs.Command           = this;
            LocProviderArgs.PendingChangeList = PendingChangeList;
            LocProvider = LocalizationProvider.GetLocalizationProvider(LocalizationProviderName, LocProviderArgs);
        }

        // Make sure the Localization configs and content is up-to-date to ensure we don't get errors later on
        if (P4Enabled)
        {
            Log("Sync necessary content to head revision");
            P4.Sync(P4Env.BuildRootP4 + "/" + LocalizationBatch.LocalizationTargetDirectory + "/Config/Localization/...");
            P4.Sync(P4Env.BuildRootP4 + "/" + LocalizationBatch.LocalizationTargetDirectory + "/Content/Localization/...");
        }

        // Generate the info we need to gather for each project
        var ProjectInfos = new List <ProjectInfo>();

        foreach (var ProjectName in LocalizationBatch.LocalizationProjectNames)
        {
            ProjectInfos.Add(GenerateProjectInfo(RootLocalizationTargetDirectory, ProjectName, LocalizationSteps));
        }

        if (LocalizationSteps.Contains("Download") && LocProvider != null)
        {
            // Export all text from our localization provider
            foreach (var ProjectInfo in ProjectInfos)
            {
                LocProvider.DownloadProjectFromLocalizationProvider(ProjectInfo.ProjectName, ProjectInfo.ImportInfo);
            }
        }

        // Setup editor arguments for SCC.
        string EditorArguments = String.Empty;

        if (P4Enabled)
        {
            EditorArguments = String.Format("-SCCProvider={0} -P4Port={1} -P4User={2} -P4Client={3} -P4Passwd={4} -P4Changelist={5} -EnableSCC -DisableSCCSubmit", "Perforce", P4Env.P4Port, P4Env.User, P4Env.Client, P4.GetAuthenticationToken(), PendingChangeList);
        }
        else
        {
            EditorArguments = String.Format("-SCCProvider={0}", "None");
        }
        EditorArguments += " -Unattended";

        // Execute commandlet for each config in each project.
        bool bLocCommandletFailed = false;

        foreach (var ProjectInfo in ProjectInfos)
        {
            foreach (var LocalizationStep in ProjectInfo.LocalizationSteps)
            {
                if (!LocalizationSteps.Contains(LocalizationStep.Name))
                {
                    continue;
                }

                var CommandletArguments = String.Format("-config=\"{0}\"", LocalizationStep.LocalizationConfigFile);

                if (!String.IsNullOrEmpty(AdditionalCommandletArguments))
                {
                    CommandletArguments += " " + AdditionalCommandletArguments;
                }

                string Arguments = String.Format("{0} -run=GatherText {1} {2}", UEProjectName, EditorArguments, CommandletArguments);
                Log("Running localization commandlet: {0}", Arguments);
                var StartTime   = DateTime.UtcNow;
                var RunResult   = Run(EditorExe, Arguments, null, 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 below)
                var RunDuration = (DateTime.UtcNow - StartTime).TotalMilliseconds;
                Log("Localization commandlet finished in {0}s", RunDuration / 1000);

                if (RunResult.ExitCode != 0)
                {
                    LogWarning("The localization commandlet exited with code {0} which likely indicates a crash. It ran with the following arguments: '{1}'", RunResult.ExitCode, Arguments);
                    bLocCommandletFailed = true;
                    break;                     // We failed a step, so don't process any other steps in this config chain
                }
            }
        }

        if (LocalizationSteps.Contains("Upload") && LocProvider != null)
        {
            if (bLocCommandletFailed)
            {
                LogWarning("Skipping upload to the localization provider due to an earlier commandlet failure.");
            }
            else
            {
                // Upload all text to our localization provider
                foreach (var ProjectInfo in ProjectInfos)
                {
                    LocProvider.UploadProjectToLocalizationProvider(ProjectInfo.ProjectName, ProjectInfo.ExportInfo);
                }
            }
        }
    }
	private void ProcessLocalizationProjects(LocalizationBatch LocalizationBatch, string UEProjectRoot, string UEProjectName, string LocalizationProviderName, List<string> LocalizationSteps, string AdditionalCommandletArguments)
	{
		var EditorExe = CombinePaths(CmdEnv.LocalRoot, @"Engine/Binaries/Win64/UE4Editor-Cmd.exe");
		var RootWorkingDirectory = CombinePaths(UEProjectRoot, LocalizationBatch.UEProjectDirectory);

		// Try and find our localization provider
		LocalizationProvider LocProvider = null;
		{
			LocalizationProvider.LocalizationProviderArgs LocProviderArgs;
			LocProviderArgs.RootWorkingDirectory = RootWorkingDirectory;
			LocProviderArgs.RemoteFilenamePrefix = LocalizationBatch.RemoteFilenamePrefix;
			LocProviderArgs.CommandUtils = this;
			LocProvider = LocalizationProvider.GetLocalizationProvider(LocalizationProviderName, LocProviderArgs);
		}

		// Make sure the Localization configs and content is up-to-date to ensure we don't get errors later on
		if (P4Enabled)
		{
			Log("Sync necessary content to head revision");
			P4.Sync(P4Env.BuildRootP4 + "/" + LocalizationBatch.UEProjectDirectory + "/Config/Localization/...");
			P4.Sync(P4Env.BuildRootP4 + "/" + LocalizationBatch.UEProjectDirectory + "/Content/Localization/...");
		}

		// Generate the info we need to gather for each project
		var ProjectInfos = new List<ProjectInfo>();
		foreach (var ProjectName in LocalizationBatch.LocalizationProjectNames)
		{
			ProjectInfos.Add(GenerateProjectInfo(RootWorkingDirectory, ProjectName, LocalizationSteps));
		}

		if (LocalizationSteps.Contains("Download") && LocProvider != null)
		{
			// Export all text from our localization provider
			foreach (var ProjectInfo in ProjectInfos)
			{
				LocProvider.DownloadProjectFromLocalizationProvider(ProjectInfo.ProjectName, ProjectInfo.ImportInfo);
			}
		}

		// Setup editor arguments for SCC.
		string EditorArguments = String.Empty;
		if (P4Enabled)
		{
			EditorArguments = String.Format("-SCCProvider={0} -P4Port={1} -P4User={2} -P4Client={3} -P4Passwd={4}", "Perforce", P4Env.P4Port, P4Env.User, P4Env.Client, P4.GetAuthenticationToken());
		}
		else
		{
			EditorArguments = String.Format("-SCCProvider={0}", "None");
		}

		// Setup commandlet arguments for SCC.
		string CommandletSCCArguments = String.Empty;
		if (P4Enabled) { CommandletSCCArguments += (String.IsNullOrEmpty(CommandletSCCArguments) ? "" : " ") + "-EnableSCC"; }
		if (!AllowSubmit) { CommandletSCCArguments += (String.IsNullOrEmpty(CommandletSCCArguments) ? "" : " ") + "-DisableSCCSubmit"; }

		// Execute commandlet for each config in each project.
		bool bLocCommandletFailed = false;
		foreach (var ProjectInfo in ProjectInfos)
		{
			foreach (var LocalizationStep in ProjectInfo.LocalizationSteps)
			{
				if (!LocalizationSteps.Contains(LocalizationStep.Name))
				{
					continue;
				}

				var CommandletArguments = String.Format("-config=\"{0}\"", LocalizationStep.LocalizationConfigFile) + (String.IsNullOrEmpty(CommandletSCCArguments) ? "" : " " + CommandletSCCArguments);

				if (!String.IsNullOrEmpty(AdditionalCommandletArguments))
				{
					CommandletArguments += " " + AdditionalCommandletArguments;
				}

				string Arguments = String.Format("{0} -run=GatherText {1} {2}", UEProjectName, EditorArguments, CommandletArguments);
				Log("Running localization commandlet: {0}", Arguments);
				var StartTime = DateTime.UtcNow;
				var RunResult = Run(EditorExe, Arguments, null, 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 below)
				var RunDuration = (DateTime.UtcNow - StartTime).TotalMilliseconds;
				Log("Localization commandlet finished in {0}s", RunDuration / 1000);

				if (RunResult.ExitCode != 0)
				{
					LogWarning("The localization commandlet exited with code {0} which likely indicates a crash. It ran with the following arguments: '{1}'", RunResult.ExitCode, Arguments);
					bLocCommandletFailed = true;
					break; // We failed a step, so don't process any other steps in this config chain
				}
			}
		}

		if (LocalizationSteps.Contains("Upload") && LocProvider != null)
		{
			if (bLocCommandletFailed)
			{
				LogWarning("Skipping upload to the localization provider due to an earlier commandlet failure.");
			}
			else
			{
				// Upload all text to our localization provider
				foreach (var ProjectInfo in ProjectInfos)
				{
					LocProvider.UploadProjectToLocalizationProvider(ProjectInfo.ProjectName, ProjectInfo.ExportInfo);
				}
			}
		}
	}