int32 UGatherTextFromSourceCommandlet::Main( const FString& Params ) { // Parse command line - we're interested in the param vals TArray<FString> Tokens; TArray<FString> Switches; TMap<FString, FString> ParamVals; UCommandlet::ParseCommandLine(*Params, Tokens, Switches, ParamVals); //Set config file const FString* ParamVal = ParamVals.Find(FString(TEXT("Config"))); FString GatherTextConfigPath; if ( ParamVal ) { GatherTextConfigPath = *ParamVal; } else { UE_LOG(LogGatherTextFromSourceCommandlet, Error, TEXT("No config specified.")); return -1; } //Set config section ParamVal = ParamVals.Find(FString(TEXT("Section"))); FString SectionName; if ( ParamVal ) { SectionName = *ParamVal; } else { UE_LOG(LogGatherTextFromSourceCommandlet, Error, TEXT("No config section specified.")); return -1; } // SearchDirectoryPaths TArray<FString> SearchDirectoryPaths; GetPathArrayFromConfig(*SectionName, TEXT("SearchDirectoryPaths"), SearchDirectoryPaths, GatherTextConfigPath); // IncludePaths (DEPRECATED) { TArray<FString> IncludePaths; GetPathArrayFromConfig(*SectionName, TEXT("IncludePaths"), IncludePaths, GatherTextConfigPath); if (IncludePaths.Num()) { SearchDirectoryPaths.Append(IncludePaths); UE_LOG(LogGatherTextFromSourceCommandlet, Warning, TEXT("IncludePaths detected in section %s. IncludePaths is deprecated, please use SearchDirectoryPaths."), *SectionName); } } if (SearchDirectoryPaths.Num() == 0) { UE_LOG(LogGatherTextFromSourceCommandlet, Error, TEXT("No search directory paths in section %s."), *SectionName); return -1; } // ExcludePathFilters TArray<FString> ExcludePathFilters; GetPathArrayFromConfig(*SectionName, TEXT("ExcludePathFilters"), ExcludePathFilters, GatherTextConfigPath); // ExcludePaths (DEPRECATED) { TArray<FString> ExcludePaths; GetPathArrayFromConfig(*SectionName, TEXT("ExcludePaths"), ExcludePaths, GatherTextConfigPath); if (ExcludePaths.Num()) { ExcludePathFilters.Append(ExcludePaths); UE_LOG(LogGatherTextFromSourceCommandlet, Warning, TEXT("ExcludePaths detected in section %s. ExcludePaths is deprecated, please use ExcludePathFilters."), *SectionName); } } // FileNameFilters TArray<FString> FileNameFilters; GetStringArrayFromConfig(*SectionName, TEXT("FileNameFilters"), FileNameFilters, GatherTextConfigPath); // SourceFileSearchFilters (DEPRECATED) { TArray<FString> SourceFileSearchFilters; GetStringArrayFromConfig(*SectionName, TEXT("SourceFileSearchFilters"), SourceFileSearchFilters, GatherTextConfigPath); if (SourceFileSearchFilters.Num()) { FileNameFilters.Append(SourceFileSearchFilters); UE_LOG(LogGatherTextFromSourceCommandlet, Warning, TEXT("SourceFileSearchFilters detected in section %s. SourceFileSearchFilters is deprecated, please use FileNameFilters."), *SectionName); } } if (FileNameFilters.Num() == 0) { UE_LOG(LogGatherTextFromSourceCommandlet, Error, TEXT("No source filters in section %s"), *SectionName); return -1; } //Ensure all filters are unique. TArray<FString> UniqueSourceFileSearchFilters; for (const FString& SourceFileSearchFilter : FileNameFilters) { UniqueSourceFileSearchFilters.AddUnique(SourceFileSearchFilter); } // Search in the root folder for each of the wildcard filters specified and build a list of files TArray<FString> AllFoundFiles; for (FString& SearchDirectoryPath : SearchDirectoryPaths) { for (const FString& UniqueSourceFileSearchFilter : UniqueSourceFileSearchFilters) { TArray<FString> RootSourceFiles; IFileManager::Get().FindFilesRecursive(RootSourceFiles, *SearchDirectoryPath, *UniqueSourceFileSearchFilter, true, false,false); for (FString& RootSourceFile : RootSourceFiles) { if (FPaths::IsRelative(RootSourceFile)) { RootSourceFile = FPaths::ConvertRelativePathToFull(RootSourceFile); } } AllFoundFiles.Append(RootSourceFiles); } } TArray<FString> FilesToProcess; TArray<FString> RemovedList; //Run through all the files found and add any that pass the exclude and filter constraints to PackageFilesToProcess for (const FString& FoundFile : AllFoundFiles) { bool bExclude = false; //Ensure it does not match the exclude paths if there are some. for (FString& ExcludePath : ExcludePathFilters) { if (FoundFile.MatchesWildcard(ExcludePath) ) { bExclude = true; RemovedList.Add(FoundFile); break; } } //If we haven't failed any checks, add it to the array of files to process. if( !bExclude ) { FilesToProcess.Add(FoundFile); } } // Return if no source files were found if( FilesToProcess.Num() == 0 ) { FString SpecifiedDirectoriesString; for (FString& SearchDirectoryPath : SearchDirectoryPaths) { SpecifiedDirectoriesString.Append(FString(SpecifiedDirectoriesString.IsEmpty() ? TEXT("") : TEXT("\n")) + FString::Printf(TEXT("+ %s"), *SearchDirectoryPath)); } for (FString& ExcludePath : ExcludePathFilters) { SpecifiedDirectoriesString.Append(FString(SpecifiedDirectoriesString.IsEmpty() ? TEXT("") : TEXT("\n")) + FString::Printf(TEXT("- %s"), *ExcludePath)); } FString SourceFileSearchFiltersString; for (const auto& Filter : UniqueSourceFileSearchFilters) { SourceFileSearchFiltersString += FString(SourceFileSearchFiltersString.IsEmpty() ? TEXT("") : TEXT(", ")) + Filter; } UE_LOG(LogGatherTextFromSourceCommandlet, Error, TEXT("The GatherTextFromSource commandlet couldn't find any source files matching (%s) in the specified directories:\n%s"), *SourceFileSearchFiltersString, *SpecifiedDirectoriesString); return -1; } // Add any manifest dependencies if they were provided TArray<FString> ManifestDependenciesList; GetPathArrayFromConfig(*SectionName, TEXT("ManifestDependencies"), ManifestDependenciesList, GatherTextConfigPath); if( !ManifestInfo->AddManifestDependencies( ManifestDependenciesList ) ) { UE_LOG(LogGatherTextFromSourceCommandlet, Error, TEXT("The GatherTextFromSource commandlet couldn't find all the specified manifest dependencies.")); return -1; } // Get the loc macros and their syntax TArray<FParsableDescriptor*> Parsables; Parsables.Add(new FDefineDescriptor()); Parsables.Add(new FUndefDescriptor()); Parsables.Add(new FCommandMacroDescriptor()); // New Localization System with Namespace as literal argument. Parsables.Add(new FStringMacroDescriptor( FString(TEXT("NSLOCTEXT")), FMacroDescriptor::FMacroArg(FMacroDescriptor::MAS_Namespace, true), FMacroDescriptor::FMacroArg(FMacroDescriptor::MAS_Identifier, true), FMacroDescriptor::FMacroArg(FMacroDescriptor::MAS_SourceText, true))); // New Localization System with Namespace as preprocessor define. Parsables.Add(new FStringMacroDescriptor( FString(TEXT("LOCTEXT")), FMacroDescriptor::FMacroArg(FMacroDescriptor::MAS_Identifier, true), FMacroDescriptor::FMacroArg(FMacroDescriptor::MAS_SourceText, true))); Parsables.Add(new FIniNamespaceDescriptor()); // Init a parse context to track the state of the file parsing FSourceFileParseContext ParseCtxt; ParseCtxt.ManifestInfo = ManifestInfo; // Parse all source files for macros and add entries to SourceParsedEntries for ( FString& SourceFile : FilesToProcess) { FString ProjectBasePath; if (!FPaths::GameDir().IsEmpty()) { ProjectBasePath = FPaths::GameDir(); } else { ProjectBasePath = FPaths::EngineDir(); } ParseCtxt.Filename = SourceFile; FPaths::MakePathRelativeTo(ParseCtxt.Filename, *ProjectBasePath); ParseCtxt.LineNumber = 0; ParseCtxt.LineText.Empty(); ParseCtxt.Namespace.Empty(); ParseCtxt.ExcludedRegion = false; ParseCtxt.WithinBlockComment = false; ParseCtxt.WithinLineComment = false; ParseCtxt.WithinStringLiteral = false; ParseCtxt.WithinNamespaceDefine = false; ParseCtxt.WithinStartingLine.Empty(); FString SourceFileText; if (!FFileHelper::LoadFileToString(SourceFileText, *SourceFile)) { UE_LOG(LogGatherTextFromSourceCommandlet, Error, TEXT("GatherTextSource failed to open file %s"), *ParseCtxt.Filename); } else { if (!ParseSourceText(SourceFileText, Parsables, ParseCtxt)) { UE_LOG(LogGatherTextFromSourceCommandlet, Warning, TEXT("GatherTextSource error(s) parsing source file %s"), *ParseCtxt.Filename); } else { if (ParseCtxt.WithinNamespaceDefine == true) { UE_LOG(LogGatherTextFromSourceCommandlet, Warning, TEXT("Non-matching LOCTEXT_NAMESPACE defines found in %s"), *ParseCtxt.Filename); } } } } // Clear parsables list safely for (int32 i=0; i<Parsables.Num(); i++) { delete Parsables[i]; } return 0; }
int32 UGatherTextFromSourceCommandlet::Main( const FString& Params ) { // Parse command line - we're interested in the param vals TArray<FString> Tokens; TArray<FString> Switches; TMap<FString, FString> ParamVals; UCommandlet::ParseCommandLine(*Params, Tokens, Switches, ParamVals); //Set config file const FString* ParamVal = ParamVals.Find(FString(TEXT("Config"))); FString GatherTextConfigPath; if ( ParamVal ) { GatherTextConfigPath = *ParamVal; } else { UE_LOG(LogGatherTextFromSourceCommandlet, Error, TEXT("No config specified.")); return -1; } //Set config section ParamVal = ParamVals.Find(FString(TEXT("Section"))); FString SectionName; if ( ParamVal ) { SectionName = *ParamVal; } else { UE_LOG(LogGatherTextFromSourceCommandlet, Error, TEXT("No config section specified.")); return -1; } //Include paths TArray<FString> IncludePaths; GetConfigArray(*SectionName, TEXT("IncludePaths"), IncludePaths, GatherTextConfigPath); if (IncludePaths.Num() == 0) { UE_LOG(LogGatherTextFromSourceCommandlet, Error, TEXT("No include paths in section %s"), *SectionName); return -1; } //Exclude paths TArray<FString> ExcludePaths; GetConfigArray(*SectionName, TEXT("ExcludePaths"), ExcludePaths, GatherTextConfigPath); // Check the config section for source filters. e.g. *.cpp TArray<FString> SourceFileSearchFilters; GetConfigArray(*SectionName, TEXT("SourceFileSearchFilters"), SourceFileSearchFilters, GatherTextConfigPath); if (SourceFileSearchFilters.Num() == 0) { UE_LOG(LogGatherTextFromSourceCommandlet, Error, TEXT("No source filters in section %s"), *SectionName); return -1; } //Ensure all filters are unique. TArray<FString> UniqueSourceFileSearchFilters; for (int32 Idx=0; Idx<SourceFileSearchFilters.Num(); Idx++) { UniqueSourceFileSearchFilters.AddUnique(SourceFileSearchFilters[Idx]); } // Search in the root folder for each of the wildcard filters specified and build a list of files TArray<FString> AllFoundFiles; for(int32 i = 0; i < IncludePaths.Num(); i++) { for (int32 SourceFileSearchIdx=0; SourceFileSearchIdx < UniqueSourceFileSearchFilters.Num(); SourceFileSearchIdx++) { TArray<FString> RootSourceFiles; IFileManager::Get().FindFilesRecursive(RootSourceFiles, *(FPaths::RootDir() + IncludePaths[i]), *UniqueSourceFileSearchFilters[SourceFileSearchIdx], true, false,false); AllFoundFiles.Append(RootSourceFiles); } } TArray<FString> FilesToProcess; TArray<FString> RemovedList; //Run through all the files found and add any that pass the include, exclude and filter constraints to PackageFilesToProcess for( int32 FileIdx=0; FileIdx < AllFoundFiles.Num(); ++FileIdx ) { bool bExclude = false; //Ensure it does not match the exclude paths if there are some. for( int32 ExcludePathIdx=0; ExcludePathIdx < ExcludePaths.Num() ; ++ExcludePathIdx ) { if( AllFoundFiles[FileIdx].MatchesWildcard( ExcludePaths[ExcludePathIdx] ) ) { bExclude = true; RemovedList.Add( AllFoundFiles[FileIdx] ); break; } } //If we haven't failed any checks, add it to the array of files to process. if( !bExclude ) { FilesToProcess.Add( AllFoundFiles[FileIdx] ); } } // Return if no source files were found if( FilesToProcess.Num() == 0 ) { UE_LOG(LogGatherTextFromSourceCommandlet, Error, TEXT("The GatherTextFromSource commandlet couldn't find any source files in the specified directories.")); return -1; } // Add any manifest dependencies if they were provided TArray<FString> ManifestDependenciesList; GetConfigArray(*SectionName, TEXT("ManifestDependencies"), ManifestDependenciesList, GatherTextConfigPath); if( !ManifestInfo->AddManifestDependencies( ManifestDependenciesList ) ) { UE_LOG(LogGatherTextFromSourceCommandlet, Error, TEXT("The GatherTextFromSource commandlet couldn't find all the specified manifest dependencies.")); return -1; } // Get the loc macros and their syntax TArray<FParsableDescriptor*> Parsables; Parsables.Add(new FDefineDescriptor()); Parsables.Add(new FUndefDescriptor()); Parsables.Add(new FCommandMacroDescriptor()); // New Localization System with Namespace as literal argument. Parsables.Add(new FStringMacroDescriptor( FString(TEXT("NSLOCTEXT")), FMacroDescriptor::FMacroArg(FMacroDescriptor::MAS_Namespace, true), FMacroDescriptor::FMacroArg(FMacroDescriptor::MAS_Identifier, true), FMacroDescriptor::FMacroArg(FMacroDescriptor::MAS_SourceText, true))); // New Localization System with Namespace as preprocessor define. Parsables.Add(new FStringMacroDescriptor( FString(TEXT("LOCTEXT")), FMacroDescriptor::FMacroArg(FMacroDescriptor::MAS_Identifier, true), FMacroDescriptor::FMacroArg(FMacroDescriptor::MAS_SourceText, true))); Parsables.Add(new FIniNamespaceDescriptor()); // Init a parse context to track the state of the file parsing FSourceFileParseContext ParseCtxt; ParseCtxt.ManifestInfo = ManifestInfo; // Parse all source files for macros and add entries to SourceParsedEntries for (int32 SourceFileIdx=0; SourceFileIdx < FilesToProcess.Num(); SourceFileIdx++) { ParseCtxt.Filename = FilesToProcess[SourceFileIdx]; ParseCtxt.LineNumber = 0; ParseCtxt.ExcludedRegion = false; ParseCtxt.WithinBlockComment = false; ParseCtxt.WithinLineComment = false; FString SourceFileText; if (!FFileHelper::LoadFileToString(SourceFileText, *ParseCtxt.Filename)) { UE_LOG(LogGatherTextFromSourceCommandlet, Error, TEXT("GatherTextSource failed to open file %s"), *ParseCtxt.Filename); } else { if (!ParseSourceText(SourceFileText, Parsables, ParseCtxt)) { UE_LOG(LogGatherTextFromSourceCommandlet, Warning, TEXT("GatherTextSource error(s) parsing source file %s"), *ParseCtxt.Filename); } } } // Clear parsables list safely for (int32 i=0; i<Parsables.Num(); i++) { delete Parsables[i]; } return 0; }