예제 #1
0
 public ProjectInfo(string InProjectName, IReadOnlyList <ProjectStepInfo> InLocalizationSteps, ProjectImportExportInfo InImportInfo, ProjectImportExportInfo InExportInfo)
 {
     ProjectName       = InProjectName;
     LocalizationSteps = InLocalizationSteps;
     ImportInfo        = InImportInfo;
     ExportInfo        = InExportInfo;
 }
	public override void DownloadProjectFromLocalizationProvider(string ProjectName, ProjectImportExportInfo ProjectImportInfo)
	{
		var XLocApiClient = CreateXLocApiClient();

		try
		{
			var AuthToken = RequestAuthTokenWithRetry(XLocApiClient);

			// Create changelist for backed up POs from XLoc.
			int XLocDownloadedPOChangeList = 0;
			if (CommandUtils.P4Enabled)
			{
				XLocDownloadedPOChangeList = CommandUtils.P4.CreateChange(CommandUtils.P4Env.Client, "XLoc downloaded PO backup.");
			}

			// Get the latest files for each culture.
			foreach (var Culture in ProjectImportInfo.CulturesToGenerate)
			{
				// Skip the native culture, as XLoc doesn't have an entry for it
				if (Culture == ProjectImportInfo.NativeCulture)
				{
					continue;
				}

				DownloadLatestPOFile(XLocApiClient, AuthToken, Culture, ProjectImportInfo, XLocDownloadedPOChangeList);
			}

			// Submit changelist for backed up POs from OneSky.
			if (CommandUtils.P4Enabled)
			{
				int SubmittedChangeList;
				CommandUtils.P4.Submit(XLocDownloadedPOChangeList, out SubmittedChangeList);
			}
		}
		finally
		{
			XLocApiClient.Close();
		}
	}
	public override void DownloadProjectFromLocalizationProvider(string ProjectName, ProjectImportExportInfo ProjectImportInfo)
	{
		var OneSkyFileName = GetOneSkyFilename(ProjectImportInfo.PortableObjectName);
		var OneSkyProject = GetOneSkyProject(ProjectName);
		var OneSkyFile = OneSkyProject.UploadedFiles.FirstOrDefault(f => f.Filename == OneSkyFileName);

		// Create changelist for backed up POs from OneSky.
		int OneSkyDownloadedPOChangeList = 0;
		if (CommandUtils.P4Enabled)
		{
			OneSkyDownloadedPOChangeList = CommandUtils.P4.CreateChange(CommandUtils.P4Env.Client, "OneSky downloaded PO backup.");
		}

		//Export
		if (OneSkyFile != null)
		{
			var CulturesToExport = new List<string>();
			foreach (var OneSkyCulture in OneSkyProject.EnabledCultures)
			{
				// Only export the OneSky cultures that we care about for this project
				if (ProjectImportInfo.CulturesToGenerate.Contains(OneSkyCulture))
				{
					CulturesToExport.Add(OneSkyCulture);
				}
			}

			ExportOneSkyFileToDirectory(OneSkyFile, new DirectoryInfo(CommandUtils.CombinePaths(RootWorkingDirectory, ProjectImportInfo.DestinationPath)), ProjectImportInfo.PortableObjectName, CulturesToExport, ProjectImportInfo.bUseCultureDirectory, OneSkyDownloadedPOChangeList);
		}

		// Submit changelist for backed up POs from OneSky.
		if (CommandUtils.P4Enabled)
		{
			int SubmittedChangeList;
			CommandUtils.P4.Submit(OneSkyDownloadedPOChangeList, out SubmittedChangeList);
		}
	}
예제 #4
0
 public virtual void UploadProjectToLocalizationProvider(string ProjectName, ProjectImportExportInfo ProjectExportInfo)
 {
     throw new AutomationException("Unimplemented UploadProjectToLocalizationProvider.");
 }
	public override void UploadProjectToLocalizationProvider(string ProjectName, ProjectImportExportInfo ProjectExportInfo)
	{
		var OneSkyProject = GetOneSkyProject(ProjectName);

		Func<string, FileInfo> GetPathForCulture = (string Culture) =>
		{
			if (ProjectExportInfo.bUseCultureDirectory)
			{
				return new FileInfo(Path.Combine(RootWorkingDirectory, ProjectExportInfo.DestinationPath, Culture, ProjectExportInfo.PortableObjectName));
			}
			else
			{
				return new FileInfo(Path.Combine(RootWorkingDirectory, ProjectExportInfo.DestinationPath, ProjectExportInfo.PortableObjectName));
			}
		};

		// Upload the .po file for the native culture first
		UploadFileToOneSky(OneSkyProject, GetPathForCulture(ProjectExportInfo.NativeCulture), ProjectExportInfo.NativeCulture);

		if (bUploadAllCultures)
		{
			// Upload the remaining .po files for the other cultures
			foreach (var Culture in ProjectExportInfo.CulturesToGenerate)
			{
				// Skip native culture as we uploaded it above
				if (Culture != ProjectExportInfo.NativeCulture)
				{
					UploadFileToOneSky(OneSkyProject, GetPathForCulture(Culture), Culture);
				}
			}
		}
	}
	public virtual void UploadProjectToLocalizationProvider(string ProjectName, ProjectImportExportInfo ProjectExportInfo)
	{
		throw new AutomationException("Unimplemented UploadProjectToLocalizationProvider.");
	}
	private void UploadLatestPOFile(TransferServiceClient TransferServiceClient, string AuthToken, string Culture, ProjectImportExportInfo ProjectExportInfo)
	{
		var SourceDirectory = new DirectoryInfo(CommandUtils.CombinePaths(RootWorkingDirectory, ProjectExportInfo.DestinationPath));
		var CultureDirectory = (ProjectExportInfo.bUseCultureDirectory) ? new DirectoryInfo(Path.Combine(SourceDirectory.FullName, Culture)) : SourceDirectory;

		var FileToUpload = new FileInfo(Path.Combine(CultureDirectory.FullName, ProjectExportInfo.PortableObjectName));
		var XLocFilename = GetXLocFilename(ProjectExportInfo.PortableObjectName);

		using (var FileStream = FileToUpload.OpenRead())
		{
			// We need to leave the language ID field blank for the native culture to avoid XLoc trying to process it as translated source, rather than raw source text
			var EpicCultureToXLocLanguageId = GetEpicCultureToXLocLanguageId();
			var LanguageId = (Culture == ProjectExportInfo.NativeCulture) ? "" : EpicCultureToXLocLanguageId[Culture];

			var FileUploadMetaData = new XLoc.Contracts.GameFileUploadInfo();
			FileUploadMetaData.CaseSensitive = false;
			FileUploadMetaData.FileName = XLocFilename;
			FileUploadMetaData.HistoricalTranslation = false;
			FileUploadMetaData.LanguageId = LanguageId;
			FileUploadMetaData.LocalizationId = Config.LocalizationId;
			FileUploadMetaData.PlatformId = "!";

			Console.WriteLine("Uploading: '{0}' as '{1}' ({2})", FileToUpload.FullName, XLocFilename, Culture);

			try
			{
				TransferServiceClient.UploadGameFile(Config.APIKey, AuthToken, FileUploadMetaData, FileToUpload.Length, FileStream);
				Console.WriteLine("[SUCCESS] Uploading: '{0}' ({1})", FileToUpload.FullName, Culture);
			}
			catch (Exception Ex)
			{
				Console.WriteLine("[FAILED] Uploading: '{0}' ({1}) - {2}", FileToUpload.FullName, Culture, Ex);
			}
		}
	}
	public override void UploadProjectToLocalizationProvider(string ProjectName, ProjectImportExportInfo ProjectExportInfo)
	{
		var XLocApiClient = CreateXLocApiClient();
		var TransferServiceClient = CreateTransferServiceClient();

		try
		{
			var AuthToken = RequestAuthTokenWithRetry(XLocApiClient);

			// Upload the .po file for the native culture first
			UploadLatestPOFile(TransferServiceClient, AuthToken, ProjectExportInfo.NativeCulture, ProjectExportInfo);

			if (bUploadAllCultures)
			{
				// Upload the remaining .po files for the other cultures
				foreach (var Culture in ProjectExportInfo.CulturesToGenerate)
				{
					// Skip native culture as we uploaded it above
					if (Culture != ProjectExportInfo.NativeCulture)
					{
						UploadLatestPOFile(TransferServiceClient, AuthToken, Culture, ProjectExportInfo);
					}
				}
			}
		}
		finally
		{
			XLocApiClient.Close();
			TransferServiceClient.Close();
		}
	}
	private void DownloadLatestPOFile(XLocApiClient XLocApiClient, string AuthToken, string Culture, ProjectImportExportInfo ProjectImportInfo, int XLocDownloadedPOChangeList)
	{
		var XLocFilename = GetXLocFilename(ProjectImportInfo.PortableObjectName);

		// This will throw if the requested culture is invalid, but we don't want to let that kill the whole gather
		var LatestBuildXml = "";
		try
		{
			var EpicCultureToXLocLanguageId = GetEpicCultureToXLocLanguageId();
			LatestBuildXml = RequestLatestBuild(XLocApiClient, AuthToken, EpicCultureToXLocLanguageId[Culture]);
		}
		catch (Exception Ex)
		{
			BuildCommand.LogWarning("RequestLatestBuild failed for {0}. {1}", Culture, Ex);
			return;
		}

		var POFileUri = "";
		var BuildsXmlDoc = new XmlDocument();
		BuildsXmlDoc.LoadXml(LatestBuildXml);

		var BuildElem = BuildsXmlDoc["Build"];
		if (BuildElem != null)
		{
			var BuildFilesElem = BuildElem["BuildFiles"];
			if (BuildFilesElem != null)
			{
				foreach (XmlNode BuildFile in BuildFilesElem)
				{
					bool IsCorrectFile = false;

					// Is this the file we want?
					var GameFileElem = BuildFile["GameFile"];
					if (GameFileElem != null)
					{
						var GameFileNameElem = GameFileElem["Name"];
						if (GameFileNameElem != null && GameFileNameElem.InnerText == XLocFilename)
						{
							IsCorrectFile = true;
						}
					}

					if (IsCorrectFile)
					{
						var BuildFileDownloadUriElem = BuildFile["DownloadUri"];
						if (BuildFileDownloadUriElem != null)
						{
							POFileUri = BuildFileDownloadUriElem.InnerText;
							break;
						}
					}
				}
			}
		}

		if (!String.IsNullOrEmpty(POFileUri))
		{
			var DestinationDirectory = new DirectoryInfo(CommandUtils.CombinePaths(RootWorkingDirectory, ProjectImportInfo.DestinationPath));
			var CultureDirectory = (ProjectImportInfo.bUseCultureDirectory) ? new DirectoryInfo(Path.Combine(DestinationDirectory.FullName, Culture)) : DestinationDirectory;
			if (!CultureDirectory.Exists)
			{
				CultureDirectory.Create();
			}

			var HTTPRequest = WebRequest.Create(POFileUri);
			HTTPRequest.Method = "GET";
			using (var Response = (HttpWebResponse)XLocUtils.GetWebResponse(HTTPRequest))
			{
				if (Response.StatusCode != HttpStatusCode.OK)
				{
					BuildCommand.LogWarning("HTTP Request to '{0}' failed. {1}", POFileUri, Response.StatusDescription);
					return;
				}

				using (var ResponseStream = Response.GetResponseStream())
				{
					var ExportFile = new FileInfo(Path.Combine(CultureDirectory.FullName, ProjectImportInfo.PortableObjectName));

					// Write out the updated PO file so that the gather commandlet will import the new data from it
					{
						var ExportFileWasReadOnly = false;
						if (ExportFile.Exists)
						{
							// We're going to clobber the existing PO file, so make sure it's writable (it may be read-only if in Perforce)
							ExportFileWasReadOnly = ExportFile.IsReadOnly;
							ExportFile.IsReadOnly = false;
						}

						using (var FileStream = ExportFile.Open(FileMode.Create))
						{
							ResponseStream.CopyTo(FileStream);
							Console.WriteLine("[SUCCESS] Exporting: '{0}' as '{1}' ({2})", XLocFilename, ExportFile.FullName, Culture);
						}

						if (ExportFileWasReadOnly)
						{
							ExportFile.IsReadOnly = true;
						}
					}

					// Also update the back-up copy so we can diff against what we got from XLoc, and what the gather commandlet produced
					{
						var ExportFileCopy = new FileInfo(Path.Combine(ExportFile.DirectoryName, String.Format("{0}_FromXLoc{1}", Path.GetFileNameWithoutExtension(ExportFile.Name), ExportFile.Extension)));

						var ExportFileCopyWasReadOnly = false;
						if (ExportFileCopy.Exists)
						{
							// We're going to clobber the existing PO file, so make sure it's writable (it may be read-only if in Perforce)
							ExportFileCopyWasReadOnly = ExportFileCopy.IsReadOnly;
							ExportFileCopy.IsReadOnly = false;
						}

						ExportFile.CopyTo(ExportFileCopy.FullName, true);

						if (ExportFileCopyWasReadOnly)
						{
							ExportFileCopy.IsReadOnly = true;
						}

						// Add/check out backed up POs from OneSky.
						if (CommandUtils.P4Enabled)
						{
							UE4Build.AddBuildProductsToChangelist(XLocDownloadedPOChangeList, new List<string>() { ExportFileCopy.FullName });
						}
					}
				}
			}
		}
	}
	private ProjectImportExportInfo GenerateProjectImportExportInfo(string LocalizationConfigFile)
	{
		var ProjectImportExportInfo = new ProjectImportExportInfo();

		var LocalizationConfig = new ConfigCacheIni(new FileReference(LocalizationConfigFile));

		if (!LocalizationConfig.GetString("CommonSettings", "DestinationPath", out ProjectImportExportInfo.DestinationPath))
		{
			throw new AutomationException("Failed to find a required config key! Section: 'CommonSettings', Key: 'DestinationPath', File: '{0}'", LocalizationConfigFile);
		}

		if (!LocalizationConfig.GetString("CommonSettings", "ManifestName", out ProjectImportExportInfo.ManifestName))
		{
			throw new AutomationException("Failed to find a required config key! Section: 'CommonSettings', Key: 'ManifestName', File: '{0}'", LocalizationConfigFile);
		}

		if (!LocalizationConfig.GetString("CommonSettings", "ArchiveName", out ProjectImportExportInfo.ArchiveName))
		{
			throw new AutomationException("Failed to find a required config key! Section: 'CommonSettings', Key: 'ArchiveName', File: '{0}'", LocalizationConfigFile);
		}

		if (!LocalizationConfig.GetString("CommonSettings", "PortableObjectName", out ProjectImportExportInfo.PortableObjectName))
		{
			throw new AutomationException("Failed to find a required config key! Section: 'CommonSettings', Key: 'PortableObjectName', File: '{0}'", LocalizationConfigFile);
		}

		if (!LocalizationConfig.GetString("CommonSettings", "NativeCulture", out ProjectImportExportInfo.NativeCulture))
		{
			throw new AutomationException("Failed to find a required config key! Section: 'CommonSettings', Key: 'NativeCulture', File: '{0}'", LocalizationConfigFile);
		}

		if (!LocalizationConfig.GetArray("CommonSettings", "CulturesToGenerate", out ProjectImportExportInfo.CulturesToGenerate))
		{
			throw new AutomationException("Failed to find a required config key! Section: 'CommonSettings', Key: 'CulturesToGenerate', File: '{0}'", LocalizationConfigFile);
		}

		if (!LocalizationConfig.GetBool("CommonSettings", "bUseCultureDirectory", out ProjectImportExportInfo.bUseCultureDirectory))
		{
			// bUseCultureDirectory is optional, default is true
			ProjectImportExportInfo.bUseCultureDirectory = true;
		}

		return ProjectImportExportInfo;
	}