applicationManager.cpp 140 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <source/utils/applicationManager.h>
  9. #include <AzCore/Asset/AssetManagerBus.h>
  10. #include <AzCore/Asset/AssetManagerComponent.h>
  11. #include <AzCore/IO/FileIO.h>
  12. #include <AzCore/Jobs/Algorithms.h>
  13. #include <AzCore/Jobs/JobManagerComponent.h>
  14. #include <AzCore/Module/DynamicModuleHandle.h>
  15. #include <AzCore/Module/ModuleManagerBus.h>
  16. #include <AzCore/Slice/SliceSystemComponent.h>
  17. #include <AzCore/Settings/SettingsRegistry.h>
  18. #include <AzCore/std/string/conversions.h>
  19. #include <AzCore/StringFunc/StringFunc.h>
  20. #include <AzCore/UserSettings/UserSettingsComponent.h>
  21. #include <AzCore/Utils/Utils.h>
  22. #include <AzFramework/Asset/AssetCatalogComponent.h>
  23. #include <AzFramework/Entity/GameEntityContextComponent.h>
  24. #include <AzFramework/FileFunc/FileFunc.h>
  25. #include <AzFramework/FileTag/FileTagComponent.h>
  26. #include <AzFramework/Input/System/InputSystemComponent.h>
  27. #include <AzFramework/Platform/PlatformDefaults.h>
  28. #include <AzFramework/Components/AzFrameworkConfigurationSystemComponent.h>
  29. #include <AzToolsFramework/Archive/ArchiveComponent.h>
  30. #include <AzToolsFramework/Asset/AssetDebugInfo.h>
  31. #include <AzToolsFramework/Asset/AssetUtils.h>
  32. #include <AzToolsFramework/AssetBundle/AssetBundleComponent.h>
  33. #include <AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalogBus.h>
  34. #include <AzToolsFramework/Prefab/PrefabSystemComponent.h>
  35. namespace AssetBundler
  36. {
  37. // Added a declaration of GetBuildTargetName which retrieves the name of the build target
  38. // The build target changes depending on which shared library/executable applicationManager.cpp
  39. // is linked to
  40. AZStd::string_view GetBuildTargetName();
  41. const char compareVariablePrefix = '$';
  42. ApplicationManager::ApplicationManager(int* argc, char*** argv, QObject* parent)
  43. : ApplicationManager(argc, argv, parent, {})
  44. {
  45. }
  46. ApplicationManager::ApplicationManager(int* argc, char*** argv, AZ::ComponentApplicationSettings componentAppSettings)
  47. : ApplicationManager(argc, argv, nullptr, AZStd::move(componentAppSettings))
  48. {
  49. }
  50. ApplicationManager::ApplicationManager(int* argc, char*** argv, QObject* parent, AZ::ComponentApplicationSettings componentAppSettings)
  51. : QObject(parent)
  52. , AzToolsFramework::ToolsApplication(argc, argv, AZStd::move(componentAppSettings))
  53. {
  54. }
  55. ApplicationManager::~ApplicationManager()
  56. {
  57. DestroyApplication();
  58. }
  59. bool ApplicationManager::Init()
  60. {
  61. AZ::Debug::TraceMessageBus::Handler::BusConnect();
  62. ComponentApplication::StartupParameters startupParameters;
  63. // The AssetBundler does not need to load gems
  64. startupParameters.m_loadDynamicModules = false;
  65. Start(AzFramework::Application::Descriptor(), startupParameters);
  66. AZ::SerializeContext* context = nullptr;
  67. AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
  68. AZ_Assert(context, "No serialize context");
  69. AzToolsFramework::AssetSeedManager::Reflect(context);
  70. AzToolsFramework::AssetFileInfoListComparison::Reflect(context);
  71. AzToolsFramework::AssetBundleSettings::Reflect(context);
  72. [[maybe_unused]] AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
  73. AZ_Assert(fileIO != nullptr, "AZ::IO::FileIOBase must be ready for use.\n");
  74. m_assetSeedManager = AZStd::make_unique<AzToolsFramework::AssetSeedManager>();
  75. AZ_TracePrintf(AssetBundler::AppWindowName, "\n");
  76. // There is no need to update the UserSettings file, so we can avoid a race condition by disabling save on shutdown
  77. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
  78. return true;
  79. }
  80. void ApplicationManager::DestroyApplication()
  81. {
  82. m_showVerboseOutput = false;
  83. m_assetSeedManager.reset();
  84. Stop();
  85. AZ::Debug::TraceMessageBus::Handler::BusDisconnect();
  86. }
  87. bool ApplicationManager::Run()
  88. {
  89. const AZ::CommandLine* parser = GetCommandLine();
  90. bool shouldPrintHelp = ShouldPrintHelp(parser);
  91. // Check for what command we are running, and if the user wants to see the Help text
  92. m_commandType = GetCommandType(parser, shouldPrintHelp);
  93. if (shouldPrintHelp)
  94. {
  95. // If someone requested the help text, it doesn't matter if their command is invalid
  96. OutputHelp(m_commandType);
  97. return true;
  98. }
  99. if (m_commandType == CommandType::Invalid)
  100. {
  101. OutputHelp(m_commandType);
  102. return false;
  103. }
  104. if (parser->HasSwitch(ProjectArg))
  105. {
  106. if (parser->GetNumSwitchValues(ProjectArg) != 1)
  107. {
  108. AZ_Error(AppWindowName, false, "Invalid command : \"--%s\" must have exactly one value.", ProjectArg);
  109. return false;
  110. }
  111. m_currentProjectName = parser->GetSwitchValue(ProjectArg, 0);
  112. AZ_TracePrintf(AssetBundler::AppWindowName, "Setting project to ( %s ).\n", m_currentProjectName.c_str());
  113. }
  114. m_showVerboseOutput = ShouldPrintVerbose(parser);
  115. m_currentProjectName = AZStd::string_view{ AZ::Utils::GetProjectName() };
  116. if (m_currentProjectName.empty())
  117. {
  118. AZ_Error(AppWindowName, false, "Unable to retrieve project name from the Settings Registry");
  119. return false;
  120. }
  121. // Gems
  122. if (!AzFramework::GetGemsInfo(m_gemInfoList, *m_settingsRegistry))
  123. {
  124. AZ_Error(AppWindowName, false, "Failed to read Gems for project: %s\n", m_currentProjectName.c_str());
  125. return false;
  126. }
  127. m_platformCatalogManager = AZStd::make_unique<AzToolsFramework::PlatformAddressedAssetCatalogManager>();
  128. InitArgValidationLists();
  129. switch (m_commandType)
  130. {
  131. case CommandType::Seeds:
  132. return RunSeedsCommands(ParseSeedsCommandData(parser));
  133. case CommandType::AssetLists:
  134. return RunAssetListsCommands(ParseAssetListsCommandData(parser));
  135. case CommandType::ComparisonRules:
  136. return RunComparisonRulesCommands(ParseComparisonRulesCommandData(parser));
  137. case CommandType::Compare:
  138. return RunCompareCommand(ParseCompareCommandData(parser));
  139. case CommandType::BundleSettings:
  140. return RunBundleSettingsCommands(ParseBundleSettingsCommandData(parser));
  141. case CommandType::Bundles:
  142. return RunBundlesCommands(ParseBundlesCommandData(parser));
  143. case CommandType::BundleSeed:
  144. return RunBundleSeedCommands(ParseBundleSeedCommandData(parser));
  145. }
  146. return false;
  147. }
  148. AZ::ComponentTypeList ApplicationManager::GetRequiredSystemComponents() const
  149. {
  150. AZ::ComponentTypeList components = AzFramework::Application::GetRequiredSystemComponents();
  151. components.emplace_back(azrtti_typeid<AzToolsFramework::AssetBundleComponent>());
  152. components.emplace_back(azrtti_typeid<AzToolsFramework::ArchiveComponent>());
  153. components.emplace_back(azrtti_typeid<AzToolsFramework::Prefab::PrefabSystemComponent>());
  154. for (auto iter = components.begin(); iter != components.end();)
  155. {
  156. if (*iter == azrtti_typeid<AzFramework::GameEntityContextComponent>() ||
  157. *iter == azrtti_typeid<AzFramework::AzFrameworkConfigurationSystemComponent>() ||
  158. *iter == azrtti_typeid<AzFramework::InputSystemComponent>() ||
  159. *iter == azrtti_typeid<AZ::SliceSystemComponent>())
  160. {
  161. // Asset Bundler does not require the above components to be active
  162. iter = components.erase(iter);
  163. }
  164. else
  165. {
  166. ++iter;
  167. }
  168. }
  169. return components;
  170. }
  171. void ApplicationManager::SetSettingsRegistrySpecializations(AZ::SettingsRegistryInterface::Specializations& specializations)
  172. {
  173. AzToolsFramework::ToolsApplication::SetSettingsRegistrySpecializations(specializations);
  174. specializations.Append(GetBuildTargetName());
  175. }
  176. ////////////////////////////////////////////////////////////////////////////////////////////
  177. // Get Generic Command Info
  178. ////////////////////////////////////////////////////////////////////////////////////////////
  179. CommandType ApplicationManager::GetCommandType(const AZ::CommandLine* parser, [[maybe_unused]] bool suppressErrors)
  180. {
  181. // Verify that the user has only typed in one sub-command
  182. size_t numMiscValues = parser->GetNumMiscValues();
  183. if (numMiscValues == 0)
  184. {
  185. AZ_Error(AppWindowName, suppressErrors, "Invalid command: Must provide a sub-command (ex: \"%s\").", AssetBundler::SeedsCommand);
  186. return CommandType::Invalid;
  187. }
  188. else if (numMiscValues > 1)
  189. {
  190. AZ_Error(AppWindowName, suppressErrors, "Invalid command: Cannot perform more than one sub-command operation at once");
  191. return CommandType::Invalid;
  192. }
  193. AZStd::string subCommand = parser->GetMiscValue(0);
  194. if (!azstricmp(subCommand.c_str(),AssetBundler::SeedsCommand))
  195. {
  196. return CommandType::Seeds;
  197. }
  198. else if (!azstricmp(subCommand.c_str(), AssetBundler::AssetListsCommand))
  199. {
  200. return CommandType::AssetLists;
  201. }
  202. else if (!azstricmp(subCommand.c_str(), AssetBundler::ComparisonRulesCommand))
  203. {
  204. return CommandType::ComparisonRules;
  205. }
  206. else if (!azstricmp(subCommand.c_str(), AssetBundler::CompareCommand))
  207. {
  208. return CommandType::Compare;
  209. }
  210. else if (!azstricmp(subCommand.c_str(), AssetBundler::BundleSettingsCommand))
  211. {
  212. return CommandType::BundleSettings;
  213. }
  214. else if (!azstricmp(subCommand.c_str(), AssetBundler::BundlesCommand))
  215. {
  216. return CommandType::Bundles;
  217. }
  218. else if (!azstricmp(subCommand.c_str(), AssetBundler::BundleSeedCommand))
  219. {
  220. return CommandType::BundleSeed;
  221. }
  222. else
  223. {
  224. AZ_Error(AppWindowName, false, "( %s ) is not a valid sub-command", subCommand.c_str());
  225. return CommandType::Invalid;
  226. }
  227. }
  228. bool ApplicationManager::ShouldPrintHelp(const AZ::CommandLine* parser)
  229. {
  230. return parser->HasSwitch(AssetBundler::HelpFlag) || parser->HasSwitch(AssetBundler::HelpFlagAlias);
  231. }
  232. bool ApplicationManager::ShouldPrintVerbose(const AZ::CommandLine* parser)
  233. {
  234. return parser->HasSwitch(AssetBundler::VerboseFlag);
  235. }
  236. void ApplicationManager::InitArgValidationLists()
  237. {
  238. m_allSeedsArgs = {
  239. SeedListFileArg,
  240. AddSeedArg,
  241. RemoveSeedArg,
  242. AddPlatformToAllSeedsFlag,
  243. RemovePlatformFromAllSeedsFlag,
  244. UpdateSeedPathArg,
  245. RemoveSeedPathArg,
  246. PrintFlag,
  247. PlatformArg,
  248. AssetCatalogFileArg,
  249. VerboseFlag,
  250. ProjectArg,
  251. IgnoreFileCaseFlag
  252. };
  253. m_allAssetListsArgs = {
  254. AssetListFileArg,
  255. SeedListFileArg,
  256. AddSeedArg,
  257. AddDefaultSeedListFilesFlag,
  258. PlatformArg,
  259. AssetCatalogFileArg,
  260. PrintFlag,
  261. DryRunFlag,
  262. GenerateDebugFileFlag,
  263. AllowOverwritesFlag,
  264. VerboseFlag,
  265. SkipArg,
  266. ProjectArg
  267. };
  268. m_allComparisonRulesArgs = {
  269. ComparisonRulesFileArg,
  270. ComparisonTypeArg,
  271. ComparisonFilePatternArg,
  272. ComparisonFilePatternTypeArg,
  273. ComparisonTokenNameArg,
  274. ComparisonFirstInputArg,
  275. ComparisonSecondInputArg,
  276. AddComparisonStepArg,
  277. RemoveComparisonStepArg,
  278. MoveComparisonStepArg,
  279. EditComparisonStepArg,
  280. PrintFlag,
  281. VerboseFlag,
  282. ProjectArg
  283. };
  284. m_allCompareArgs =
  285. {
  286. ComparisonRulesFileArg,
  287. ComparisonTypeArg,
  288. ComparisonFilePatternArg,
  289. ComparisonFilePatternTypeArg,
  290. CompareFirstFileArg,
  291. CompareSecondFileArg,
  292. CompareOutputFileArg,
  293. ComparePrintArg,
  294. IntersectionCountArg,
  295. AllowOverwritesFlag,
  296. PlatformArg,
  297. VerboseFlag,
  298. ProjectArg
  299. };
  300. m_allBundleSettingsArgs = {
  301. BundleSettingsFileArg,
  302. AssetListFileArg,
  303. OutputBundlePathArg,
  304. BundleVersionArg,
  305. MaxBundleSizeArg,
  306. PlatformArg,
  307. PrintFlag,
  308. VerboseFlag,
  309. ProjectArg
  310. };
  311. m_allBundlesArgs = {
  312. BundleSettingsFileArg,
  313. AssetListFileArg,
  314. OutputBundlePathArg,
  315. BundleVersionArg,
  316. MaxBundleSizeArg,
  317. PlatformArg,
  318. AllowOverwritesFlag,
  319. VerboseFlag,
  320. ProjectArg
  321. };
  322. m_allBundleSeedArgs = {
  323. BundleSettingsFileArg,
  324. AddSeedArg,
  325. OutputBundlePathArg,
  326. BundleVersionArg,
  327. MaxBundleSizeArg,
  328. PlatformArg,
  329. AssetCatalogFileArg,
  330. AllowOverwritesFlag,
  331. VerboseFlag,
  332. ProjectArg
  333. };
  334. }
  335. ////////////////////////////////////////////////////////////////////////////////////////////
  336. // Store Detailed Command Info
  337. ////////////////////////////////////////////////////////////////////////////////////////////
  338. AZ::Outcome<SeedsParams, AZStd::string> ApplicationManager::ParseSeedsCommandData(const AZ::CommandLine* parser)
  339. {
  340. using namespace AzToolsFramework;
  341. auto validateArgsOutcome = ValidateInputArgs(parser, m_allSeedsArgs);
  342. if (!validateArgsOutcome.IsSuccess())
  343. {
  344. OutputHelpSeeds();
  345. return AZ::Failure(validateArgsOutcome.TakeError());
  346. }
  347. SeedsParams params;
  348. params.m_ignoreFileCase = parser->HasSwitch(IgnoreFileCaseFlag);
  349. // Read in Seed List Files arg
  350. auto requiredArgOutcome = GetFilePathArg(parser, SeedListFileArg, SeedsCommand, true);
  351. if (!requiredArgOutcome.IsSuccess())
  352. {
  353. return AZ::Failure(requiredArgOutcome.GetError());
  354. }
  355. bool checkFileCase = true;
  356. // Seed List files do not have platform-specific file names
  357. params.m_seedListFile = FilePath(requiredArgOutcome.GetValue(), checkFileCase, params.m_ignoreFileCase);
  358. if (!params.m_seedListFile.IsValid())
  359. {
  360. return AZ::Failure(params.m_seedListFile.ErrorString());
  361. }
  362. // Read in Add/Remove Platform to All Seeds flag
  363. params.m_addPlatformToAllSeeds = parser->HasSwitch(AddPlatformToAllSeedsFlag);
  364. params.m_removePlatformFromAllSeeds = parser->HasSwitch(RemovePlatformFromAllSeedsFlag);
  365. if (params.m_addPlatformToAllSeeds && params.m_removePlatformFromAllSeeds)
  366. {
  367. return AZ::Failure(AZStd::string::format("Invalid command: Unable to run \"--%s\" and \"--%s\" at the same time.", AssetBundler::AddPlatformToAllSeedsFlag, AssetBundler::RemovePlatformFromAllSeedsFlag));
  368. }
  369. if ((params.m_addPlatformToAllSeeds || params.m_removePlatformFromAllSeeds) && !parser->HasSwitch(PlatformArg))
  370. {
  371. return AZ::Failure(AZStd::string::format("Invalid command: When running \"--%s\" or \"--%s\", the \"--%s\" arg is required.", AddPlatformToAllSeedsFlag, RemovePlatformFromAllSeedsFlag, PlatformArg));
  372. }
  373. // Read in Platform arg
  374. auto platformOutcome = GetPlatformArg(parser);
  375. if (!platformOutcome.IsSuccess())
  376. {
  377. return AZ::Failure(platformOutcome.GetError());
  378. }
  379. params.m_platformFlags = GetInputPlatformFlagsOrEnabledPlatformFlags(platformOutcome.GetValue());
  380. // Read in Asset Catalog File arg
  381. auto argOutcome = GetFilePathArg(parser, AssetCatalogFileArg, SeedsCommand);
  382. if (!argOutcome.IsSuccess())
  383. {
  384. return AZ::Failure(argOutcome.GetError());
  385. }
  386. if (!argOutcome.IsSuccess())
  387. {
  388. params.m_assetCatalogFile = FilePath(argOutcome.GetValue(), checkFileCase, params.m_ignoreFileCase);
  389. if (!params.m_assetCatalogFile.IsValid())
  390. {
  391. return AZ::Failure(params.m_assetCatalogFile.ErrorString());
  392. }
  393. }
  394. // Read in Add Seed arg
  395. params.m_addSeedList = GetAddSeedArgList(parser);
  396. // Read in Remove Seed arg
  397. size_t numRemoveSeedArgs = 0;
  398. if (parser->HasSwitch(RemoveSeedArg))
  399. {
  400. numRemoveSeedArgs = parser->GetNumSwitchValues(RemoveSeedArg);
  401. for (size_t removeSeedIndex = 0; removeSeedIndex < numRemoveSeedArgs; ++removeSeedIndex)
  402. {
  403. params.m_removeSeedList.push_back(parser->GetSwitchValue(RemoveSeedArg, removeSeedIndex));
  404. }
  405. }
  406. // Read Update Seed Path arg
  407. params.m_updateSeedPathHint = parser->HasSwitch(UpdateSeedPathArg);
  408. // Read Update Seed Path arg
  409. params.m_removeSeedPathHint = parser->HasSwitch(RemoveSeedPathArg);
  410. // Read in Print flag
  411. params.m_print = parser->HasSwitch(PrintFlag);
  412. return AZ::Success(params);
  413. }
  414. AZStd::string ApplicationManager::GetBinaryArgOptionFailure(const char* arg1, const char* arg2)
  415. {
  416. const char FailureMessage[] = "Missing argument: Either %s or %s must be supplied";
  417. return AZStd::string::format(FailureMessage, arg1, arg2);
  418. }
  419. AZ::Outcome<AssetListsParams, AZStd::string> ApplicationManager::ParseAssetListsCommandData(const AZ::CommandLine* parser)
  420. {
  421. auto validateArgsOutcome = ValidateInputArgs(parser, m_allAssetListsArgs);
  422. if (!validateArgsOutcome.IsSuccess())
  423. {
  424. OutputHelpAssetLists();
  425. return AZ::Failure(validateArgsOutcome.TakeError());
  426. }
  427. AssetListsParams params;
  428. // Read in Platform arg
  429. auto platformOutcome = GetPlatformArg(parser);
  430. if (!platformOutcome.IsSuccess())
  431. {
  432. return AZ::Failure(platformOutcome.GetError());
  433. }
  434. params.m_platformFlags = GetInputPlatformFlagsOrEnabledPlatformFlags(platformOutcome.GetValue());
  435. // Read in Print flag
  436. params.m_print = parser->HasSwitch(PrintFlag);
  437. // Read in Asset List File arg
  438. auto requiredArgOutcome = GetFilePathArg(parser, AssetListFileArg, AssetListsCommand, false);
  439. params.m_assetListFile = FilePath(requiredArgOutcome.GetValue());
  440. if (!params.m_print && !params.m_assetListFile.IsValid())
  441. {
  442. return AZ::Failure(GetBinaryArgOptionFailure(PrintFlag,AssetListFileArg));
  443. }
  444. // Read in Seed List File arg
  445. size_t numSeedListFiles = parser->GetNumSwitchValues(SeedListFileArg);
  446. for (size_t seedListFileIndex = 0; seedListFileIndex < numSeedListFiles; ++seedListFileIndex)
  447. {
  448. params.m_seedListFiles.emplace_back(FilePath(parser->GetSwitchValue(SeedListFileArg, seedListFileIndex)));
  449. }
  450. // Read in Add Seed arg
  451. params.m_addSeedList = GetAddSeedArgList(parser);
  452. // Read in Skip arg
  453. params.m_skipList = GetSkipArgList(parser);
  454. // Read in Add Default Seed List Files arg
  455. params.m_addDefaultSeedListFiles = parser->HasSwitch(AddDefaultSeedListFilesFlag);
  456. // Read in Asset Catalog File arg
  457. auto argOutcome = GetFilePathArg(parser, AssetCatalogFileArg, AssetListsCommand);
  458. if (!argOutcome.IsSuccess())
  459. {
  460. return AZ::Failure(argOutcome.GetError());
  461. }
  462. if (!argOutcome.IsSuccess())
  463. {
  464. params.m_assetCatalogFile = FilePath(argOutcome.GetValue());
  465. }
  466. // Read in Dry Run flag
  467. params.m_dryRun = parser->HasSwitch(DryRunFlag);
  468. // Read in Generate Debug File flag
  469. params.m_generateDebugFile = parser->HasSwitch(GenerateDebugFileFlag);
  470. // Read in Allow Overwrites flag
  471. params.m_allowOverwrites = parser->HasSwitch(AllowOverwritesFlag);
  472. return AZ::Success(params);
  473. }
  474. AZ::Outcome<ComparisonRulesParams, AZStd::string> ApplicationManager::ParseComparisonRulesCommandData(const AZ::CommandLine* parser)
  475. {
  476. auto validateArgsOutcome = ValidateInputArgs(parser, m_allComparisonRulesArgs);
  477. if (!validateArgsOutcome.IsSuccess())
  478. {
  479. OutputHelpComparisonRules();
  480. return AZ::Failure(validateArgsOutcome.TakeError());
  481. }
  482. ScopedTraceHandler traceHandler;
  483. ComparisonRulesParams params;
  484. auto requiredArgOutcome = GetFilePathArg(parser, ComparisonRulesFileArg, ComparisonRulesCommand, true);
  485. if (!requiredArgOutcome.IsSuccess())
  486. {
  487. return AZ::Failure(requiredArgOutcome.GetError());
  488. }
  489. params.m_comparisonRulesFile = FilePath(requiredArgOutcome.GetValue());
  490. if (params.m_comparisonRulesFile.AbsolutePath().empty())
  491. {
  492. return AZ::Failure(AZStd::string::format("Invalid command: \"--%s\" cannot be empty.", ComparisonRulesFileArg));
  493. }
  494. // Read in Add Comparison Step arg
  495. if (parser->HasSwitch(AddComparisonStepArg))
  496. {
  497. size_t numInputs = parser->GetNumSwitchValues(AddComparisonStepArg);
  498. switch (numInputs)
  499. {
  500. case 0:
  501. params.m_comparisonRulesStepAction = ComparisonRulesStepAction::AddToEnd;
  502. break;
  503. case 1:
  504. params.m_comparisonRulesStepAction = ComparisonRulesStepAction::Add;
  505. params.m_destinationLine = static_cast<size_t>(AZ::StringFunc::ToInt(parser->GetSwitchValue(AddComparisonStepArg, 0).c_str()));
  506. break;
  507. default:
  508. return AZ::Failure(AZStd::string::format("Invalid command: \"--%s\" cannot have more than one input value.", AddComparisonStepArg));
  509. }
  510. // Read in what the user wants to add
  511. auto parseComparisonTypesOutcome = ParseComparisonTypesAndPatterns(parser, params);
  512. if (!parseComparisonTypesOutcome.IsSuccess())
  513. {
  514. return AZ::Failure(parseComparisonTypesOutcome.GetError());
  515. }
  516. }
  517. // Read in Remove Comparison Step arg
  518. if (parser->HasSwitch(RemoveComparisonStepArg))
  519. {
  520. if (params.m_comparisonRulesStepAction != ComparisonRulesStepAction::Default)
  521. {
  522. return AZ::Failure(AZStd::string::format(
  523. "Invalid command: Only one of the following args may be used in a single command: \"--%s\", \"--%s\", \"--%s\", \"--%s\".",
  524. AddComparisonStepArg, RemoveComparisonStepArg, MoveComparisonStepArg, EditComparisonStepArg));
  525. }
  526. if (parser->GetNumSwitchValues(RemoveComparisonStepArg) != 1)
  527. {
  528. return AZ::Failure(AZStd::string::format(
  529. "Invalid command: \"--%s\" requires exatly one input value (the line number you wish to remove).",
  530. RemoveComparisonStepArg));
  531. }
  532. params.m_comparisonRulesStepAction = ComparisonRulesStepAction::Remove;
  533. params.m_initialLine = static_cast<size_t>(AZ::StringFunc::ToInt(parser->GetSwitchValue(RemoveComparisonStepArg, 0).c_str()));
  534. }
  535. // Read in Move Comparison Step arg
  536. if (parser->HasSwitch(MoveComparisonStepArg))
  537. {
  538. if (params.m_comparisonRulesStepAction != ComparisonRulesStepAction::Default)
  539. {
  540. return AZ::Failure(AZStd::string::format(
  541. "Invalid command: Only one of the following args may be used in a single command: \"--%s\", \"--%s\", \"--%s\", \"--%s\".",
  542. AddComparisonStepArg, RemoveComparisonStepArg, MoveComparisonStepArg, EditComparisonStepArg));
  543. }
  544. if (parser->GetNumSwitchValues(MoveComparisonStepArg) != 2)
  545. {
  546. return AZ::Failure(AZStd::string::format(
  547. "Invalid command: \"--%s\" requires exatly two input values (the line number of the Comparison Step you wish to move, and the destination line)",
  548. MoveComparisonStepArg));
  549. }
  550. params.m_comparisonRulesStepAction = ComparisonRulesStepAction::Move;
  551. params.m_initialLine = static_cast<size_t>(AZ::StringFunc::ToInt(parser->GetSwitchValue(MoveComparisonStepArg, 0).c_str()));
  552. params.m_destinationLine = static_cast<size_t>(AZ::StringFunc::ToInt(parser->GetSwitchValue(MoveComparisonStepArg, 1).c_str()));
  553. }
  554. // Read in Edit Comparison Step arg
  555. if (parser->HasSwitch(EditComparisonStepArg))
  556. {
  557. if (params.m_comparisonRulesStepAction != ComparisonRulesStepAction::Default)
  558. {
  559. return AZ::Failure(AZStd::string::format(
  560. "Invalid command: Only one of the following args may be used in a single command: \"--%s\", \"--%s\", \"--%s\", \"--%s\".",
  561. AddComparisonStepArg, RemoveComparisonStepArg, MoveComparisonStepArg, EditComparisonStepArg));
  562. }
  563. if (parser->GetNumSwitchValues(EditComparisonStepArg) != 1)
  564. {
  565. return AZ::Failure(AZStd::string::format(
  566. "Invalid command: \"--%s\" requires exactly one input value (the line number of the Comparison Step you wish to edit)",
  567. EditComparisonStepArg));
  568. }
  569. params.m_comparisonRulesStepAction = ComparisonRulesStepAction::Edit;
  570. params.m_initialLine = static_cast<size_t>(AZ::StringFunc::ToInt(parser->GetSwitchValue(EditComparisonStepArg, 0).c_str()));
  571. // When editing a Comparison Step, we can only accept one input for every value type
  572. auto parseComparisonTypesForEditOutcome = ParseComparisonTypesAndPatternsForEditCommand(parser, params);
  573. if (!parseComparisonTypesForEditOutcome.IsSuccess())
  574. {
  575. return AZ::Failure(parseComparisonTypesForEditOutcome.GetError());
  576. }
  577. }
  578. auto parseFirstAndSecondInputsOutcome = ParseComparisonRulesFirstAndSecondInputArgs(parser, params);
  579. if (!parseFirstAndSecondInputsOutcome.IsSuccess())
  580. {
  581. return AZ::Failure(parseFirstAndSecondInputsOutcome.GetError());
  582. }
  583. if (parser->HasSwitch(ComparisonTypeArg) &&
  584. !parser->HasSwitch(AddComparisonStepArg) &&
  585. !parser->HasSwitch(EditComparisonStepArg))
  586. {
  587. return AZ::Failure(AZStd::string::format(
  588. "Invalid command: \"--%s\" cannot be used without one of the following operations: \"--%s\", \"--%s\".",
  589. ComparisonTypeArg, AddComparisonStepArg, EditComparisonStepArg));
  590. }
  591. for (const auto& comparisonType : params.m_comparisonTypeList)
  592. {
  593. if (comparisonType == AzToolsFramework::AssetFileInfoListComparison::ComparisonType::IntersectionCount)
  594. {
  595. return AZ::Failure(AZStd::string::format("Adding compare operation ( %s ) to comparison rule file is not supported currently.", AzToolsFramework::AssetFileInfoListComparison::ComparisonTypeNames[aznumeric_cast<AZ::u8>(AzToolsFramework::AssetFileInfoListComparison::ComparisonType::IntersectionCount)]));
  596. }
  597. }
  598. // Read in Print flag
  599. params.m_print = parser->HasSwitch(PrintFlag);
  600. return AZ::Success(params);
  601. }
  602. AZ::Outcome<void, AZStd::string> ApplicationManager::ParseComparisonTypesAndPatterns(const AZ::CommandLine* parser, ComparisonRulesParams& params)
  603. {
  604. int filePatternsConsumed = 0;
  605. size_t numComparisonTypes = parser->GetNumSwitchValues(ComparisonTypeArg);
  606. size_t numFilePatterns = parser->GetNumSwitchValues(ComparisonFilePatternArg);
  607. size_t numPatternTypes = parser->GetNumSwitchValues(ComparisonFilePatternTypeArg);
  608. size_t numIntersectionCount = parser->GetNumSwitchValues(IntersectionCountArg);
  609. if (numIntersectionCount > 1)
  610. {
  611. return AZ::Failure(AZStd::string::format("Invalid command: \"--%s\" must have exactly one value.", IntersectionCountArg));
  612. }
  613. params.m_intersectionCount = AZStd::stoi(parser->GetSwitchValue(IntersectionCountArg, 0));
  614. size_t numTokenNames = parser->GetNumSwitchValues(ComparisonTokenNameArg);
  615. if (numTokenNames > 0 && numComparisonTypes != numTokenNames)
  616. {
  617. return AZ::Failure(AZStd::string::format(
  618. "Number of comparisonTypes ( %zu ) and tokenNames ( %zu ) must match. Token values can always be edited later using the \"--%s\" and \"--%s\" args.",
  619. numComparisonTypes, numTokenNames, EditComparisonStepArg, ComparisonTokenNameArg));
  620. }
  621. if (numPatternTypes != numFilePatterns)
  622. {
  623. return AZ::Failure(AZStd::string::format("Number of filePatternTypes ( %zu ) and filePatterns ( %zu ) must match.", numPatternTypes, numFilePatterns));
  624. }
  625. for (size_t comparisonTypeIndex = 0; comparisonTypeIndex < numComparisonTypes; ++comparisonTypeIndex)
  626. {
  627. auto comparisonTypeOutcome = ParseComparisonType(parser->GetSwitchValue(ComparisonTypeArg, comparisonTypeIndex));
  628. if (!comparisonTypeOutcome.IsSuccess())
  629. {
  630. return AZ::Failure(comparisonTypeOutcome.GetError());
  631. }
  632. auto comparisonType = comparisonTypeOutcome.GetValue();
  633. if (comparisonType == AzToolsFramework::AssetFileInfoListComparison::ComparisonType::FilePattern)
  634. {
  635. if (filePatternsConsumed >= numFilePatterns)
  636. {
  637. return AZ::Failure(AZStd::string::format("Number of file patterns comparisons exceeded number of file patterns provided ( %zu ).", numFilePatterns));
  638. }
  639. params.m_filePatternList.emplace_back(parser->GetSwitchValue(ComparisonFilePatternArg, filePatternsConsumed));
  640. auto filePatternTypeOutcome = ParseFilePatternType(parser->GetSwitchValue(ComparisonFilePatternTypeArg, filePatternsConsumed));
  641. if (!filePatternTypeOutcome.IsSuccess())
  642. {
  643. return AZ::Failure(filePatternTypeOutcome.GetError());
  644. }
  645. params.m_filePatternTypeList.emplace_back(filePatternTypeOutcome.GetValue());
  646. filePatternsConsumed++;
  647. }
  648. else
  649. {
  650. params.m_filePatternList.emplace_back("");
  651. params.m_filePatternTypeList.emplace_back(AzToolsFramework::AssetFileInfoListComparison::FilePatternType::Default);
  652. }
  653. if (numTokenNames > 0)
  654. {
  655. AZStd::string tokenName = parser->GetSwitchValue(ComparisonTokenNameArg, comparisonTypeIndex);
  656. AzToolsFramework::AssetFileInfoListComparison::FormatOutputToken(tokenName);
  657. params.m_tokenNamesList.emplace_back(tokenName);
  658. }
  659. else
  660. {
  661. params.m_tokenNamesList.emplace_back("");
  662. }
  663. params.m_comparisonTypeList.emplace_back(comparisonType);
  664. }
  665. if (filePatternsConsumed != numFilePatterns)
  666. {
  667. return AZ::Failure(AZStd::string::format("Number of provided file patterns exceeded the number of file pattern comparisons ( %zu ).", numFilePatterns));
  668. }
  669. return AZ::Success();
  670. }
  671. AZ::Outcome<void, AZStd::string> ApplicationManager::ParseComparisonTypesAndPatternsForEditCommand(const AZ::CommandLine* parser, ComparisonRulesParams& params)
  672. {
  673. if (parser->HasSwitch(ComparisonTypeArg))
  674. {
  675. size_t numComparisonTypes = parser->GetNumSwitchValues(ComparisonTypeArg);
  676. if (numComparisonTypes > 1)
  677. {
  678. return AZ::Failure(AZStd::string::format(
  679. "Invalid command: when using the \"--%s\" arg, the \"--%s\" arg can accept no more than one input value.",
  680. EditComparisonStepArg, ComparisonTypeArg));
  681. }
  682. auto comparisonTypeOutcome = ParseComparisonType(parser->GetSwitchValue(ComparisonTypeArg, 0));
  683. if (!comparisonTypeOutcome.IsSuccess())
  684. {
  685. return AZ::Failure(comparisonTypeOutcome.GetError());
  686. }
  687. params.m_comparisonTypeList.emplace_back(comparisonTypeOutcome.GetValue());
  688. }
  689. if (parser->HasSwitch(ComparisonFilePatternTypeArg))
  690. {
  691. size_t numPatternTypes = parser->GetNumSwitchValues(ComparisonFilePatternTypeArg);
  692. if (numPatternTypes > 1)
  693. {
  694. return AZ::Failure(AZStd::string::format(
  695. "Invalid command: when using the \"--%s\" arg, the \"--%s\" arg can accept no more than one input value.",
  696. EditComparisonStepArg, ComparisonFilePatternTypeArg));
  697. }
  698. auto filePatternTypeOutcome = ParseFilePatternType(parser->GetSwitchValue(ComparisonFilePatternTypeArg, 0));
  699. if (!filePatternTypeOutcome.IsSuccess())
  700. {
  701. return AZ::Failure(filePatternTypeOutcome.GetError());
  702. }
  703. params.m_filePatternTypeList.emplace_back(filePatternTypeOutcome.GetValue());
  704. }
  705. if (parser->HasSwitch(ComparisonFilePatternArg))
  706. {
  707. size_t numFilePatterns = parser->GetNumSwitchValues(ComparisonFilePatternArg);
  708. switch (numFilePatterns)
  709. {
  710. case 0:
  711. // Our CLI parser will not return empty strings, so we need an extra case to check if a user wants to remove a FilePattern
  712. params.m_filePatternList.emplace_back("");
  713. break;
  714. case 1:
  715. params.m_filePatternList.emplace_back(parser->GetSwitchValue(ComparisonFilePatternArg, 0));
  716. break;
  717. default:
  718. return AZ::Failure(AZStd::string::format(
  719. "Invalid command: when using the \"--%s\" arg, the \"--%s\" arg can accept no more than one input value.",
  720. EditComparisonStepArg, ComparisonFilePatternArg));
  721. break;
  722. }
  723. }
  724. if (parser->HasSwitch(ComparisonTokenNameArg))
  725. {
  726. AZStd::string tokenName;
  727. size_t numTokenNames = parser->GetNumSwitchValues(ComparisonTokenNameArg);
  728. switch (numTokenNames)
  729. {
  730. case 0:
  731. // Our CLI parser will not return empty strings, so we need an extra case to check if a user wants to remove a Token altogether
  732. params.m_tokenNamesList.emplace_back("");
  733. break;
  734. case 1:
  735. tokenName = parser->GetSwitchValue(ComparisonTokenNameArg, 0);
  736. AzToolsFramework::AssetFileInfoListComparison::FormatOutputToken(tokenName);
  737. params.m_tokenNamesList.emplace_back(tokenName);
  738. break;
  739. default:
  740. return AZ::Failure(AZStd::string::format(
  741. "Invalid command: when using the \"--%s\" arg, the \"--%s\" arg can accept no more than one input value.",
  742. EditComparisonStepArg, ComparisonTokenNameArg));
  743. break;
  744. }
  745. }
  746. return AZ::Success();
  747. }
  748. AZ::Outcome<void, AZStd::string> ApplicationManager::ParseComparisonRulesFirstAndSecondInputArgs(const AZ::CommandLine* parser, ComparisonRulesParams& params)
  749. {
  750. if (params.m_comparisonTypeList.size() > 1 && (parser->HasSwitch(ComparisonFirstInputArg) || parser->HasSwitch(ComparisonSecondInputArg)))
  751. {
  752. return AZ::Failure(AZStd::string::format(
  753. "Invalid command: the \"--%s\" and \"--%s\" args can only operate on one Comparison Step at a time.",
  754. ComparisonFirstInputArg, ComparisonSecondInputArg));
  755. }
  756. size_t numInputs;
  757. AZStd::string inputStr;
  758. if (parser->HasSwitch(ComparisonFirstInputArg))
  759. {
  760. numInputs = parser->GetNumSwitchValues(ComparisonFirstInputArg);
  761. switch (numInputs)
  762. {
  763. case 0:
  764. // Our CLI parser will not return empty strings, so we need an extra case to check if a user wants to remove an input altogether
  765. params.m_firstInputList.emplace_back("");
  766. break;
  767. case 1:
  768. inputStr = parser->GetSwitchValue(ComparisonFirstInputArg, 0);
  769. if (LooksLikePath(inputStr))
  770. {
  771. return AZ::Failure(AZStd::string::format(
  772. "Invalid command: the \"--%s\" arg only accepts Tokens as inputs. Paths are not valid inputs.",
  773. ComparisonFirstInputArg));
  774. }
  775. AzToolsFramework::AssetFileInfoListComparison::FormatOutputToken(inputStr);
  776. params.m_firstInputList.emplace_back(inputStr);
  777. break;
  778. default:
  779. return AZ::Failure(AZStd::string::format(
  780. "Invalid command: when using the \"--%s\" arg, the \"--%s\" arg can accept no more than one input value.",
  781. EditComparisonStepArg, ComparisonFirstInputArg));
  782. break;
  783. }
  784. }
  785. if (parser->HasSwitch(ComparisonSecondInputArg))
  786. {
  787. numInputs = parser->GetNumSwitchValues(ComparisonSecondInputArg);
  788. switch (numInputs)
  789. {
  790. case 0:
  791. // Our CLI parser will not return empty strings, so we need an extra case to check if a user wants to remove an input altogether
  792. params.m_secondInputList.emplace_back("");
  793. break;
  794. case 1:
  795. inputStr = parser->GetSwitchValue(ComparisonSecondInputArg, 0);
  796. if (LooksLikePath(inputStr))
  797. {
  798. return AZ::Failure(AZStd::string::format(
  799. "Invalid command: the \"--%s\" arg only accepts Tokens as inputs. Paths are not valid inputs.",
  800. ComparisonSecondInputArg));
  801. }
  802. AzToolsFramework::AssetFileInfoListComparison::FormatOutputToken(inputStr);
  803. params.m_secondInputList.emplace_back(inputStr);
  804. break;
  805. default:
  806. return AZ::Failure(AZStd::string::format(
  807. "Invalid command: when using the \"--%s\" arg, the \"--%s\" arg can accept no more than one input value.",
  808. EditComparisonStepArg, ComparisonSecondInputArg));
  809. break;
  810. }
  811. }
  812. return AZ::Success();
  813. }
  814. AZ::Outcome<ComparisonParams, AZStd::string> ApplicationManager::ParseCompareCommandData(const AZ::CommandLine* parser)
  815. {
  816. auto validateArgsOutcome = ValidateInputArgs(parser, m_allCompareArgs);
  817. if (!validateArgsOutcome.IsSuccess())
  818. {
  819. OutputHelpCompare();
  820. return AZ::Failure(validateArgsOutcome.TakeError());
  821. }
  822. ComparisonParams params;
  823. // Read in Platform arg
  824. auto platformOutcome = GetPlatformArg(parser);
  825. if (!platformOutcome.IsSuccess())
  826. {
  827. return AZ::Failure(platformOutcome.GetError());
  828. }
  829. params.m_platformFlags = GetInputPlatformFlagsOrEnabledPlatformFlags(platformOutcome.GetValue());
  830. AZStd::string inferredPlatform;
  831. // read in input files (first and second)
  832. for (size_t idx = 0; idx < parser->GetNumSwitchValues(CompareFirstFileArg); idx++)
  833. {
  834. AZStd::string value = parser->GetSwitchValue(CompareFirstFileArg, idx);
  835. if (!value.starts_with(compareVariablePrefix)) // Don't make this a path if it starts with the variable prefix
  836. {
  837. FilePath path = FilePath(value);
  838. value = path.AbsolutePath();
  839. inferredPlatform = AzToolsFramework::GetPlatformIdentifier(value);
  840. }
  841. params.m_firstCompareFile.emplace_back(AZStd::move(value));
  842. }
  843. for (size_t idx = 0; idx < parser->GetNumSwitchValues(CompareSecondFileArg); idx++)
  844. {
  845. AZStd::string value = parser->GetSwitchValue(CompareSecondFileArg, idx);
  846. if (!value.starts_with(compareVariablePrefix)) // Don't make this a path if it starts with the variable prefix
  847. {
  848. FilePath path = FilePath(value);
  849. value = path.AbsolutePath();
  850. }
  851. params.m_secondCompareFile.emplace_back(AZStd::move(value));
  852. }
  853. // read in output files
  854. for (size_t idx = 0; idx < parser->GetNumSwitchValues(CompareOutputFileArg); idx++)
  855. {
  856. AZStd::string value = parser->GetSwitchValue(CompareOutputFileArg, idx);
  857. if (!value.starts_with(compareVariablePrefix)) // Don't make this a path if it starts with the variable prefix
  858. {
  859. FilePath path = FilePath(value, inferredPlatform);
  860. value = path.AbsolutePath();
  861. }
  862. params.m_outputs.emplace_back(AZStd::move(value));
  863. }
  864. // Make Path object for existing rules file to load
  865. AZ::Outcome< AZStd::string, AZStd::string> pathArgOutcome = GetFilePathArg(parser, ComparisonRulesFileArg, CompareCommand, false);
  866. if (!pathArgOutcome.IsSuccess())
  867. {
  868. return AZ::Failure(pathArgOutcome.GetError());
  869. }
  870. params.m_comparisonRulesFile = FilePath(pathArgOutcome.GetValue());
  871. // Parse info for additional rules
  872. auto comparisonParseOutcome = ParseComparisonTypesAndPatterns(parser, params.m_comparisonRulesParams);
  873. if (!comparisonParseOutcome.IsSuccess())
  874. {
  875. return AZ::Failure(comparisonParseOutcome.GetError());
  876. }
  877. for (size_t idx = 0; idx < parser->GetNumSwitchValues(ComparePrintArg); idx++)
  878. {
  879. AZStd::string value = parser->GetSwitchValue(ComparePrintArg, idx);
  880. if (!value.starts_with(compareVariablePrefix)) // Don't make this a path if it starts with the variable prefix
  881. {
  882. FilePath path = FilePath(value);
  883. value = path.AbsolutePath();
  884. }
  885. params.m_printComparisons.emplace_back(AZStd::move(value));
  886. }
  887. params.m_printLast = parser->HasSwitch(ComparePrintArg) && params.m_printComparisons.empty();
  888. if (params.m_comparisonRulesParams.m_intersectionCount && (params.m_outputs.size() != 0 && params.m_outputs.size() != 1))
  889. {
  890. return AZ::Failure(AZStd::string::format("Invalid command: \"--%s\" must have either be 0 or 1 value for compare operation of type ( %s ).",
  891. CompareOutputFileArg, AzToolsFramework::AssetFileInfoListComparison::ComparisonTypeNames[aznumeric_cast<AZ::u8>(AzToolsFramework::AssetFileInfoListComparison::ComparisonType::IntersectionCount)]));
  892. }
  893. // Read in Allow Overwrites flag
  894. params.m_allowOverwrites = parser->HasSwitch(AllowOverwritesFlag);
  895. return AZ::Success(params);
  896. }
  897. AZ::Outcome<BundleSettingsParams, AZStd::string> ApplicationManager::ParseBundleSettingsCommandData(const AZ::CommandLine* parser)
  898. {
  899. auto validateArgsOutcome = ValidateInputArgs(parser, m_allBundleSettingsArgs);
  900. if (!validateArgsOutcome.IsSuccess())
  901. {
  902. OutputHelpBundleSettings();
  903. return AZ::Failure(validateArgsOutcome.TakeError());
  904. }
  905. BundleSettingsParams params;
  906. // Read in Platform arg
  907. auto platformOutcome = GetPlatformArg(parser);
  908. if (!platformOutcome.IsSuccess())
  909. {
  910. return AZ::Failure(platformOutcome.GetError());
  911. }
  912. params.m_platformFlags = GetInputPlatformFlagsOrEnabledPlatformFlags(platformOutcome.GetValue());
  913. // Read in Bundle Settings File arg
  914. auto requiredArgOutcome = GetFilePathArg(parser, BundleSettingsFileArg, BundleSettingsCommand, true);
  915. if (!requiredArgOutcome.IsSuccess())
  916. {
  917. return AZ::Failure(requiredArgOutcome.GetError());
  918. }
  919. params.m_bundleSettingsFile = FilePath(requiredArgOutcome.GetValue());
  920. // Read in Asset List File arg
  921. auto argOutcome = GetFilePathArg(parser, AssetListFileArg, BundleSettingsCommand);
  922. if (!argOutcome.IsSuccess())
  923. {
  924. return AZ::Failure(argOutcome.GetError());
  925. }
  926. if (!argOutcome.GetValue().empty())
  927. {
  928. params.m_assetListFile = FilePath(argOutcome.GetValue());
  929. }
  930. // Read in Output Bundle Path arg
  931. argOutcome = GetFilePathArg(parser, OutputBundlePathArg, BundleSettingsCommand);
  932. if (!argOutcome.IsSuccess())
  933. {
  934. return AZ::Failure(argOutcome.GetError());
  935. }
  936. if (!argOutcome.GetValue().empty())
  937. {
  938. params.m_outputBundlePath = FilePath(argOutcome.GetValue());
  939. }
  940. // Read in Bundle Version arg
  941. if (parser->HasSwitch(BundleVersionArg))
  942. {
  943. if (parser->GetNumSwitchValues(BundleVersionArg) != 1)
  944. {
  945. return AZ::Failure(AZStd::string::format("Invalid command: \"--%s\" must have exactly one value.", BundleVersionArg));
  946. }
  947. params.m_bundleVersion = AZStd::stoi(parser->GetSwitchValue(BundleVersionArg, 0));
  948. }
  949. // Read in Max Bundle Size arg
  950. if (parser->HasSwitch(MaxBundleSizeArg))
  951. {
  952. if (parser->GetNumSwitchValues(MaxBundleSizeArg) != 1)
  953. {
  954. return AZ::Failure(AZStd::string::format("Invalid command: \"--%s\" must have exactly one value.", MaxBundleSizeArg));
  955. }
  956. params.m_maxBundleSizeInMB = AZStd::stoi(parser->GetSwitchValue(MaxBundleSizeArg, 0));
  957. }
  958. // Read in Print flag
  959. params.m_print = parser->HasSwitch(PrintFlag);
  960. return AZ::Success(params);
  961. }
  962. AZ::Outcome<BundlesParamsList, AZStd::string> ApplicationManager::ParseBundleSettingsAndOverrides(const AZ::CommandLine* parser, const char* commandName)
  963. {
  964. // Read in Bundle Settings File args
  965. auto bundleSettingsOutcome = GetArgsList<FilePath>(parser, BundleSettingsFileArg, commandName);
  966. if (!bundleSettingsOutcome.IsSuccess())
  967. {
  968. return AZ::Failure(bundleSettingsOutcome.GetError());
  969. }
  970. // Read in Asset List File args
  971. auto assetListOutcome = GetArgsList<FilePath>(parser, AssetListFileArg, commandName);
  972. if (!assetListOutcome.IsSuccess())
  973. {
  974. return AZ::Failure(assetListOutcome.GetError());
  975. }
  976. // Read in Output Bundle Path args
  977. auto bundleOutputPathOutcome = GetArgsList<FilePath>(parser, OutputBundlePathArg, commandName);
  978. if (!bundleOutputPathOutcome.IsSuccess())
  979. {
  980. return AZ::Failure(bundleOutputPathOutcome.GetError());
  981. }
  982. AZStd::vector<FilePath> bundleSettingsFileList = bundleSettingsOutcome.TakeValue();
  983. AZStd::vector<FilePath> assetListFileList = assetListOutcome.TakeValue();
  984. AZStd::vector<FilePath> outputBundleFileList = bundleOutputPathOutcome.TakeValue();
  985. size_t bundleSettingListSize = bundleSettingsFileList.size();
  986. size_t assetFileListSize = assetListFileList.size();
  987. size_t outputBundleListSize = outputBundleFileList.size();
  988. // * We are validating the following cases here
  989. // * AssetFileList should always be equal to outputBundleList size even if they are of zero length.
  990. // * BundleSettingList can be a zero size list if the number of elements in assetFileList matches the number of elements in outputBundleList.
  991. // * If bundleSettingList contains non zero elements than either it should have the same number of elements as in assetFileList or the number of elements in assetFileList should be zero.
  992. if (bundleSettingListSize)
  993. {
  994. if (assetFileListSize != outputBundleListSize)
  995. {
  996. return AZ::Failure(AZStd::string::format("Invalid command: \"--%s\" and \"--%s\" are required and should contain the same number of args.", AssetListFileArg, OutputBundlePathArg));
  997. }
  998. else if (bundleSettingListSize != assetFileListSize && assetFileListSize != 0)
  999. {
  1000. return AZ::Failure(AZStd::string::format("Invalid command: \"--%s\", \"--%s\" and \"--%s\" should contain the same number of args.", BundleSettingsFileArg, AssetListFileArg, OutputBundlePathArg));
  1001. }
  1002. }
  1003. else
  1004. {
  1005. if (assetFileListSize != outputBundleListSize)
  1006. {
  1007. return AZ::Failure(AZStd::string::format("Invalid command: \"--%s\" and \"--%s\" are required and should contain the same number of args.", AssetListFileArg, OutputBundlePathArg));
  1008. }
  1009. }
  1010. size_t expectedListSize = AZStd::max(assetFileListSize, bundleSettingListSize);
  1011. // Read in Bundle Version args
  1012. auto bundleVersionOutcome = GetArgsList<AZStd::string>(parser, BundleVersionArg, commandName);
  1013. if (!bundleVersionOutcome.IsSuccess())
  1014. {
  1015. return AZ::Failure(bundleVersionOutcome.GetError());
  1016. }
  1017. AZStd::vector<AZStd::string> bundleVersionList = bundleVersionOutcome.TakeValue();
  1018. size_t bundleVersionListSize = bundleVersionList.size();
  1019. if (bundleVersionListSize != expectedListSize && bundleVersionListSize >= 2)
  1020. {
  1021. if (expectedListSize != 1)
  1022. {
  1023. return AZ::Failure(AZStd::string::format("Invalid command: Number of args in \"--%s\" can either be zero, one or %zu. Actual size detected %zu.", BundleVersionArg, expectedListSize, bundleVersionListSize));
  1024. }
  1025. else
  1026. {
  1027. return AZ::Failure(AZStd::string::format("Invalid command: Number of args in \"--%s\" is %zu. Expected number of args is one.", BundleVersionArg, bundleVersionListSize ));
  1028. }
  1029. }
  1030. // Read in Max Bundle Size args
  1031. auto maxBundleSizeOutcome = GetArgsList<AZStd::string>(parser, MaxBundleSizeArg, commandName);
  1032. if (!maxBundleSizeOutcome.IsSuccess())
  1033. {
  1034. return AZ::Failure(maxBundleSizeOutcome.GetError());
  1035. }
  1036. AZStd::vector<AZStd::string> maxBundleSizeList = maxBundleSizeOutcome.TakeValue();
  1037. size_t maxBundleListSize = maxBundleSizeList.size();
  1038. if (maxBundleListSize != expectedListSize && maxBundleListSize >= 2)
  1039. {
  1040. if (expectedListSize != 1)
  1041. {
  1042. return AZ::Failure(AZStd::string::format("Invalid command: Number of args in \"--%s\" can either be zero, one or %zu. Actual size detected %zu.", MaxBundleSizeArg, expectedListSize, maxBundleListSize));
  1043. }
  1044. else
  1045. {
  1046. return AZ::Failure(AZStd::string::format("Invalid command: Number of args in \"--%s\" is %zu. Expected number of args is one.", MaxBundleSizeArg, maxBundleListSize));
  1047. }
  1048. }
  1049. // Read in Platform arg
  1050. auto platformOutcome = GetPlatformArg(parser);
  1051. if (!platformOutcome.IsSuccess())
  1052. {
  1053. return AZ::Failure(platformOutcome.GetError());
  1054. }
  1055. // Read in Allow Overwrites flag
  1056. bool allowOverwrites = parser->HasSwitch(AllowOverwritesFlag);
  1057. BundlesParamsList bundleParamsList;
  1058. for (int idx = 0; idx < expectedListSize; idx++)
  1059. {
  1060. BundlesParams bundleParams;
  1061. bundleParams.m_bundleSettingsFile = bundleSettingListSize ? bundleSettingsFileList[idx] : FilePath();
  1062. bundleParams.m_assetListFile = assetFileListSize ? assetListFileList[idx] : FilePath();
  1063. bundleParams.m_outputBundlePath = outputBundleListSize ? outputBundleFileList[idx] : FilePath();
  1064. if (bundleVersionListSize)
  1065. {
  1066. bundleParams.m_bundleVersion = bundleVersionListSize == 1 ? AZStd::stoi(bundleVersionList[0]) : AZStd::stoi(bundleVersionList[idx]);
  1067. }
  1068. if (maxBundleListSize)
  1069. {
  1070. bundleParams.m_maxBundleSizeInMB = maxBundleListSize == 1 ? AZStd::stoi(maxBundleSizeList[0]) : AZStd::stoi(maxBundleSizeList[idx]);
  1071. }
  1072. bundleParams.m_platformFlags = platformOutcome.GetValue();
  1073. bundleParams.m_allowOverwrites = allowOverwrites;
  1074. bundleParamsList.emplace_back(bundleParams);
  1075. }
  1076. return AZ::Success(bundleParamsList);
  1077. }
  1078. AZ::Outcome<BundlesParamsList, AZStd::string> ApplicationManager::ParseBundlesCommandData(const AZ::CommandLine* parser)
  1079. {
  1080. auto validateArgsOutcome = ValidateInputArgs(parser, m_allBundlesArgs);
  1081. if (!validateArgsOutcome.IsSuccess())
  1082. {
  1083. OutputHelpBundles();
  1084. return AZ::Failure(validateArgsOutcome.TakeError());
  1085. }
  1086. auto parseSettingsOutcome = ParseBundleSettingsAndOverrides(parser, BundlesCommand);
  1087. if (!parseSettingsOutcome.IsSuccess())
  1088. {
  1089. return AZ::Failure(parseSettingsOutcome.GetError());
  1090. }
  1091. return AZ::Success(parseSettingsOutcome.TakeValue());
  1092. }
  1093. AZ::Outcome<BundleSeedParams, AZStd::string> ApplicationManager::ParseBundleSeedCommandData(const AZ::CommandLine* parser)
  1094. {
  1095. auto validateArgsOutcome = ValidateInputArgs(parser, m_allBundleSeedArgs);
  1096. if (!validateArgsOutcome.IsSuccess())
  1097. {
  1098. OutputHelpBundleSeed();
  1099. return AZ::Failure(validateArgsOutcome.TakeError());
  1100. }
  1101. BundleSeedParams params;
  1102. params.m_addSeedList = GetAddSeedArgList(parser);
  1103. auto parseSettingsOutcome = ParseBundleSettingsAndOverrides(parser, BundleSeedCommand);
  1104. if (!parseSettingsOutcome.IsSuccess())
  1105. {
  1106. return AZ::Failure(parseSettingsOutcome.GetError());
  1107. }
  1108. BundlesParamsList paramsList = parseSettingsOutcome.TakeValue();
  1109. params.m_bundleParams = paramsList[0];
  1110. return AZ::Success(params);
  1111. }
  1112. AZ::Outcome<void, AZStd::string> ApplicationManager::ValidateInputArgs(const AZ::CommandLine* parser, const AZStd::vector<const char*>& validArgList)
  1113. {
  1114. constexpr AZStd::string_view ApplicationArgList = "/O3DE/AzCore/Application/ValidCommandOptions";
  1115. AZStd::vector<AZStd::string> validApplicationArgs;
  1116. if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
  1117. {
  1118. settingsRegistry->GetObject(validApplicationArgs, ApplicationArgList);
  1119. }
  1120. for (const auto& paramInfo : *parser)
  1121. {
  1122. // Skip positional arguments
  1123. if (paramInfo.m_option.empty())
  1124. {
  1125. continue;
  1126. }
  1127. bool isValidArg = false;
  1128. for (const auto& validArg : validArgList)
  1129. {
  1130. if (AZ::StringFunc::Equal(paramInfo.m_option, validArg))
  1131. {
  1132. isValidArg = true;
  1133. break;
  1134. }
  1135. }
  1136. for (const auto& validArg : validApplicationArgs)
  1137. {
  1138. if (AZ::StringFunc::Equal(paramInfo.m_option, validArg))
  1139. {
  1140. isValidArg = true;
  1141. break;
  1142. }
  1143. }
  1144. if (!isValidArg)
  1145. {
  1146. return AZ::Failure(AZStd::string::format(R"(Invalid argument: "--%s" is not a valid argument for this sub-command.)", paramInfo.m_option.c_str()));
  1147. }
  1148. }
  1149. return AZ::Success();
  1150. }
  1151. AZ::Outcome<AZStd::string, AZStd::string> ApplicationManager::GetFilePathArg(const AZ::CommandLine* parser, const char* argName, const char* subCommandName, bool isRequired)
  1152. {
  1153. if (!parser->HasSwitch(argName))
  1154. {
  1155. if (isRequired)
  1156. {
  1157. return AZ::Failure(AZStd::string::format("Invalid command: \"--%s\" is required when running \"%s\".", argName, subCommandName));
  1158. }
  1159. return AZ::Success(AZStd::string());
  1160. }
  1161. if (parser->GetNumSwitchValues(argName) != 1)
  1162. {
  1163. return AZ::Failure(AZStd::string::format("Invalid command: \"--%s\" must have exactly one value.", argName));
  1164. }
  1165. return AZ::Success(parser->GetSwitchValue(argName, 0));
  1166. }
  1167. template <typename T>
  1168. AZ::Outcome<AZStd::vector<T>, AZStd::string> ApplicationManager::GetArgsList(const AZ::CommandLine* parser, const char* argName, const char* subCommandName, bool isRequired)
  1169. {
  1170. AZStd::vector<T> args;
  1171. if (!parser->HasSwitch(argName))
  1172. {
  1173. if (isRequired)
  1174. {
  1175. return AZ::Failure(AZStd::string::format("Invalid command: \"--%s\" is required when running \"%s\".", argName, subCommandName));
  1176. }
  1177. return AZ::Success(args);
  1178. }
  1179. size_t numValues = parser->GetNumSwitchValues(argName);
  1180. for (int idx = 0; idx < numValues; ++idx)
  1181. {
  1182. args.emplace_back(T(parser->GetSwitchValue(argName, idx)));
  1183. }
  1184. return AZ::Success(args);
  1185. }
  1186. AZ::Outcome<AzFramework::PlatformFlags, AZStd::string> ApplicationManager::GetPlatformArg(const AZ::CommandLine* parser)
  1187. {
  1188. using namespace AzFramework;
  1189. PlatformFlags platform = AzFramework::PlatformFlags::Platform_NONE;
  1190. if (!parser->HasSwitch(PlatformArg))
  1191. {
  1192. return AZ::Success(platform);
  1193. }
  1194. size_t numValues = parser->GetNumSwitchValues(PlatformArg);
  1195. if (numValues <= 0)
  1196. {
  1197. return AZ::Failure(AZStd::string::format("Invalid command: \"--%s\" must have at least one value.", PlatformArg));
  1198. }
  1199. for (int platformIdx = 0; platformIdx < numValues; ++platformIdx)
  1200. {
  1201. AZStd::string platformStr = parser->GetSwitchValue(PlatformArg, platformIdx);
  1202. platform |= AzFramework::PlatformHelper::GetPlatformFlag(platformStr);
  1203. }
  1204. return AZ::Success(platform);
  1205. }
  1206. AzFramework::PlatformFlags ApplicationManager::GetInputPlatformFlagsOrEnabledPlatformFlags(AzFramework::PlatformFlags inputPlatformFlags)
  1207. {
  1208. using namespace AzToolsFramework;
  1209. if (inputPlatformFlags != AzFramework::PlatformFlags::Platform_NONE)
  1210. {
  1211. return inputPlatformFlags;
  1212. }
  1213. // If no platform was specified, defaulting to platforms specified in the asset processor config files
  1214. AzFramework::PlatformFlags platformFlags = GetEnabledPlatformFlags(
  1215. AZStd::string_view{ AZ::Utils::GetEnginePath() },
  1216. AZStd::string_view{ AZ::Utils::GetProjectPath() });
  1217. [[maybe_unused]] auto platformsString = AzFramework::PlatformHelper::GetCommaSeparatedPlatformList(platformFlags);
  1218. AZ_TracePrintf(AppWindowName, "No platform specified, defaulting to platforms ( %s ).\n", platformsString.c_str());
  1219. return platformFlags;
  1220. }
  1221. AZStd::vector<AZStd::string> ApplicationManager::GetAddSeedArgList(const AZ::CommandLine* parser)
  1222. {
  1223. AZStd::vector<AZStd::string> addSeedList;
  1224. size_t numAddSeedArgs = parser->GetNumSwitchValues(AddSeedArg);
  1225. for (size_t addSeedIndex = 0; addSeedIndex < numAddSeedArgs; ++addSeedIndex)
  1226. {
  1227. addSeedList.push_back(parser->GetSwitchValue(AddSeedArg, addSeedIndex));
  1228. }
  1229. return addSeedList;
  1230. }
  1231. AZStd::vector<AZStd::string> ApplicationManager::GetSkipArgList(const AZ::CommandLine* parser)
  1232. {
  1233. AZStd::vector<AZStd::string> skipList;
  1234. size_t numArgs = parser->GetNumSwitchValues(SkipArg);
  1235. for (size_t argIndex = 0; argIndex < numArgs; ++argIndex)
  1236. {
  1237. skipList.push_back(parser->GetSwitchValue(SkipArg, argIndex));
  1238. }
  1239. return skipList;
  1240. }
  1241. bool ApplicationManager::SeedsOperationRequiresCatalog(const SeedsParams& params)
  1242. {
  1243. return params.m_addSeedList.size() || params.m_addPlatformToAllSeeds || params.m_updateSeedPathHint || params.m_print;
  1244. }
  1245. ////////////////////////////////////////////////////////////////////////////////////////////
  1246. // Run Commands
  1247. ////////////////////////////////////////////////////////////////////////////////////////////
  1248. bool ApplicationManager::RunSeedsCommands(const AZ::Outcome<SeedsParams, AZStd::string>& paramsOutcome)
  1249. {
  1250. using namespace AzFramework;
  1251. if (!paramsOutcome.IsSuccess())
  1252. {
  1253. AZ_Error(AppWindowName, false, paramsOutcome.GetError().c_str());
  1254. return false;
  1255. }
  1256. SeedsParams params = paramsOutcome.GetValue();
  1257. if (SeedsOperationRequiresCatalog(params))
  1258. {
  1259. // Asset Catalog
  1260. auto catalogOutcome = InitAssetCatalog(params.m_platformFlags, params.m_assetCatalogFile.AbsolutePath());
  1261. if (!catalogOutcome.IsSuccess())
  1262. {
  1263. AZ_Error(AppWindowName, false, catalogOutcome.GetError().c_str());
  1264. return false;
  1265. }
  1266. }
  1267. // Seed List File
  1268. auto seedOutcome = LoadSeedListFile(params.m_seedListFile.AbsolutePath(), params.m_platformFlags);
  1269. if (!seedOutcome.IsSuccess())
  1270. {
  1271. AZ_Error(AppWindowName, false, seedOutcome.GetError().c_str());
  1272. return false;
  1273. }
  1274. for (const PlatformId platformId : AzFramework::PlatformHelper::GetPlatformIndices(params.m_platformFlags))
  1275. {
  1276. // Add Seeds
  1277. PlatformFlags platformFlag = AzFramework::PlatformHelper::GetPlatformFlagFromPlatformIndex(platformId);
  1278. auto cacheFolderPath = AssetBundler::GetProjectCacheFolderPath();
  1279. AZ::IO::Path cachePath;
  1280. if (cacheFolderPath.IsSuccess())
  1281. {
  1282. cachePath = cacheFolderPath.GetValue() / AZ::PlatformDefaults::PlatformHelper::GetPlatformName(platformId);
  1283. }
  1284. for (const AZStd::string& assetPath : params.m_addSeedList)
  1285. {
  1286. if (AZ::StringFunc::Contains(assetPath, '*'))
  1287. {
  1288. auto filter = cachePath / assetPath;
  1289. AZStd::string path = filter.ParentPath().Native();
  1290. AZStd::string ext = filter.Filename().Native();
  1291. bool bRecursive = AZ::StringFunc::Contains(filter.Filename().Native(), "**");
  1292. // we search all files and filter by extension later
  1293. // because recursive is not working with extension
  1294. auto result = AzFramework::FileFunc::FindFilesInPath(path, "*", bRecursive);
  1295. if (result.IsSuccess())
  1296. {
  1297. auto list = result.GetValue();
  1298. for (auto& file : list)
  1299. {
  1300. if (AZStd::wildcard_match(ext, file))
  1301. {
  1302. AZ::IO::Path filepath(file);
  1303. filepath = filepath.LexicallyRelative(cachePath);
  1304. m_assetSeedManager->AddSeedAsset(filepath.Native(), platformFlag);
  1305. }
  1306. }
  1307. }
  1308. }
  1309. else
  1310. {
  1311. m_assetSeedManager->AddSeedAsset(assetPath, platformFlag);
  1312. }
  1313. }
  1314. // Remove Seeds
  1315. for (const AZStd::string& assetPath : params.m_removeSeedList)
  1316. {
  1317. m_assetSeedManager->RemoveSeedAsset(assetPath, platformFlag);
  1318. }
  1319. // Add Platform to All Seeds
  1320. if (params.m_addPlatformToAllSeeds)
  1321. {
  1322. m_assetSeedManager->AddPlatformToAllSeeds(platformId);
  1323. }
  1324. // Remove Platform from All Seeds
  1325. if (params.m_removePlatformFromAllSeeds)
  1326. {
  1327. m_assetSeedManager->RemovePlatformFromAllSeeds(platformId);
  1328. }
  1329. }
  1330. if (params.m_updateSeedPathHint)
  1331. {
  1332. m_assetSeedManager->UpdateSeedPath();
  1333. }
  1334. if (params.m_removeSeedPathHint)
  1335. {
  1336. m_assetSeedManager->RemoveSeedPath();
  1337. }
  1338. if (params.m_print)
  1339. {
  1340. PrintSeedList(params.m_seedListFile.AbsolutePath());
  1341. }
  1342. // Save
  1343. AZ_TracePrintf(AssetBundler::AppWindowName, "Saving Seed List to ( %s )...\n", params.m_seedListFile.AbsolutePath().c_str());
  1344. if (!m_assetSeedManager->Save(params.m_seedListFile.AbsolutePath()))
  1345. {
  1346. AZ_Error(AssetBundler::AppWindowName, false, "Unable to save Seed List to ( %s ).", params.m_seedListFile.AbsolutePath().c_str());
  1347. return false;
  1348. }
  1349. AZ_TracePrintf(AssetBundler::AppWindowName, "Save successful!\n");
  1350. return true;
  1351. }
  1352. bool ApplicationManager::RunAssetListsCommands(const AZ::Outcome<AssetListsParams, AZStd::string>& paramsOutcome)
  1353. {
  1354. using namespace AzFramework;
  1355. if (!paramsOutcome.IsSuccess())
  1356. {
  1357. AZ_Error(AppWindowName, false, paramsOutcome.GetError().c_str());
  1358. return false;
  1359. }
  1360. AssetListsParams params = paramsOutcome.GetValue();
  1361. // Asset Catalog
  1362. auto catalogOutcome = InitAssetCatalog(params.m_platformFlags, params.m_assetCatalogFile.AbsolutePath());
  1363. if (!catalogOutcome.IsSuccess())
  1364. {
  1365. AZ_Error(AppWindowName, false, catalogOutcome.GetError().c_str());
  1366. return false;
  1367. }
  1368. // Seed List Files
  1369. AZ::Outcome<void, AZStd::string> seedListOutcome;
  1370. AZStd::string seedListFileAbsolutePath;
  1371. for (const FilePath& seedListFile : params.m_seedListFiles)
  1372. {
  1373. seedListFileAbsolutePath = seedListFile.AbsolutePath();
  1374. if (!AZ::IO::FileIOBase::GetInstance()->Exists(seedListFileAbsolutePath.c_str()))
  1375. {
  1376. AZ_Error(AppWindowName, false, "Cannot load Seed List file ( %s ): File does not exist.\n", seedListFileAbsolutePath.c_str());
  1377. return false;
  1378. }
  1379. seedListOutcome = LoadSeedListFile(seedListFileAbsolutePath, params.m_platformFlags);
  1380. if (!seedListOutcome.IsSuccess())
  1381. {
  1382. AZ_Error(AppWindowName, false, seedListOutcome.GetError().c_str());
  1383. return false;
  1384. }
  1385. }
  1386. // Add Default Seed List Files
  1387. if (params.m_addDefaultSeedListFiles)
  1388. {
  1389. AZStd::unordered_map<AZStd::string, AZStd::string> defaultSeedListFiles = GetDefaultSeedListFiles(GetEngineRoot(), AZ::Utils::GetProjectPath(),
  1390. m_gemInfoList, params.m_platformFlags);
  1391. if (defaultSeedListFiles.empty())
  1392. {
  1393. // Error has already been thrown
  1394. return false;
  1395. }
  1396. for (const auto& seedListFile : defaultSeedListFiles)
  1397. {
  1398. seedListOutcome = LoadSeedListFile(seedListFile.first, params.m_platformFlags);
  1399. if (!seedListOutcome.IsSuccess())
  1400. {
  1401. AZ_Error(AppWindowName, false, seedListOutcome.GetError().c_str());
  1402. return false;
  1403. }
  1404. }
  1405. AZStd::vector<AZStd::string> defaultSeeds = GetDefaultSeeds(AZ::Utils::GetProjectPath(), m_currentProjectName);
  1406. if (defaultSeeds.empty())
  1407. {
  1408. // Error has already been thrown
  1409. return false;
  1410. }
  1411. for (const auto& seed : defaultSeeds)
  1412. {
  1413. m_assetSeedManager->AddSeedAsset(seed, params.m_platformFlags);
  1414. }
  1415. }
  1416. if (!RunPlatformSpecificAssetListCommands(params, params.m_platformFlags))
  1417. {
  1418. return false;
  1419. }
  1420. return true;
  1421. }
  1422. bool ApplicationManager::RunComparisonRulesCommands(const AZ::Outcome<ComparisonRulesParams, AZStd::string>& paramsOutcome)
  1423. {
  1424. using namespace AzToolsFramework;
  1425. if (!paramsOutcome.IsSuccess())
  1426. {
  1427. AZ_Error(AppWindowName, false, paramsOutcome.GetError().c_str());
  1428. return false;
  1429. }
  1430. ComparisonRulesParams params = paramsOutcome.GetValue();
  1431. AssetFileInfoListComparison comparisonOperations;
  1432. // Read the input ComparisonRules file into memory. If it does not already exist, we are going to create a new file.
  1433. if (AZ::IO::FileIOBase::GetInstance()->Exists(params.m_comparisonRulesFile.AbsolutePath().c_str()))
  1434. {
  1435. auto rulesFileLoadOutcome = AssetFileInfoListComparison::Load(params.m_comparisonRulesFile.AbsolutePath());
  1436. if (!rulesFileLoadOutcome.IsSuccess())
  1437. {
  1438. AZ_Error(AppWindowName, false, rulesFileLoadOutcome.GetError().c_str());
  1439. return false;
  1440. }
  1441. comparisonOperations = rulesFileLoadOutcome.GetValue();
  1442. }
  1443. // Perform any editing operations (no need to throw errors on failure, they are already thrown elsewhere)
  1444. switch (params.m_comparisonRulesStepAction)
  1445. {
  1446. case(ComparisonRulesStepAction::Add):
  1447. if (!ConvertRulesParamsToComparisonData(params, comparisonOperations, params.m_destinationLine))
  1448. {
  1449. return false;
  1450. }
  1451. break;
  1452. case(ComparisonRulesStepAction::AddToEnd):
  1453. if (!ConvertRulesParamsToComparisonData(params, comparisonOperations, comparisonOperations.GetNumComparisonSteps()))
  1454. {
  1455. return false;
  1456. }
  1457. break;
  1458. case(ComparisonRulesStepAction::Remove):
  1459. if (!comparisonOperations.RemoveComparisonStep(params.m_initialLine))
  1460. {
  1461. return false;
  1462. }
  1463. break;
  1464. case(ComparisonRulesStepAction::Move):
  1465. if (!comparisonOperations.MoveComparisonStep(params.m_initialLine, params.m_destinationLine))
  1466. {
  1467. return false;
  1468. }
  1469. break;
  1470. case(ComparisonRulesStepAction::Edit):
  1471. if (!EditComparisonData(params, comparisonOperations, params.m_initialLine))
  1472. {
  1473. return false;
  1474. }
  1475. break;
  1476. }
  1477. if (params.m_print)
  1478. {
  1479. PrintComparisonRules(comparisonOperations, params.m_comparisonRulesFile.AbsolutePath());
  1480. }
  1481. // Attempt to save
  1482. if (params.m_comparisonRulesStepAction != ComparisonRulesStepAction::Default)
  1483. {
  1484. AZ_TracePrintf(AssetBundler::AppWindowName, "Saving Comparison Rules file to ( %s )...\n", params.m_comparisonRulesFile.AbsolutePath().c_str());
  1485. if (!comparisonOperations.Save(params.m_comparisonRulesFile.AbsolutePath().c_str()))
  1486. {
  1487. AZ_Error(AssetBundler::AppWindowName, false, "Failed to save Comparison Rules file ( %s ).", params.m_comparisonRulesFile.AbsolutePath().c_str());
  1488. return false;
  1489. }
  1490. AZ_TracePrintf(AssetBundler::AppWindowName, "Save successful!\n");
  1491. }
  1492. return true;
  1493. }
  1494. bool ApplicationManager::ConvertRulesParamsToComparisonData(const ComparisonRulesParams& params, AzToolsFramework::AssetFileInfoListComparison& assetListComparison, size_t startingIndex)
  1495. {
  1496. using namespace AzToolsFramework;
  1497. for (int idx = 0; idx < params.m_comparisonTypeList.size(); idx++)
  1498. {
  1499. AssetFileInfoListComparison::ComparisonData comparisonData;
  1500. comparisonData.m_comparisonType = params.m_comparisonTypeList[idx];
  1501. comparisonData.m_filePattern = params.m_filePatternList[idx];
  1502. comparisonData.m_filePatternType = params.m_filePatternTypeList[idx];
  1503. comparisonData.m_output = params.m_tokenNamesList[idx];
  1504. comparisonData.m_intersectionCount = params.m_intersectionCount;
  1505. if (!params.m_firstInputList.empty())
  1506. {
  1507. comparisonData.m_firstInput = params.m_firstInputList[idx];
  1508. }
  1509. if (comparisonData.m_comparisonType != AssetFileInfoListComparison::ComparisonType::FilePattern)
  1510. {
  1511. if (!params.m_secondInputList.empty())
  1512. {
  1513. comparisonData.m_secondInput = params.m_secondInputList[idx];
  1514. }
  1515. }
  1516. if (!assetListComparison.AddComparisonStep(comparisonData, startingIndex))
  1517. {
  1518. // Error has already been thrown
  1519. return false;
  1520. }
  1521. ++startingIndex;
  1522. }
  1523. return true;
  1524. }
  1525. bool ApplicationManager::EditComparisonData(const ComparisonRulesParams& params, AzToolsFramework::AssetFileInfoListComparison& assetListComparison, size_t index)
  1526. {
  1527. using namespace AzToolsFramework;
  1528. // Errors are thrown by the Asset List Comparison functions, no need to write our own here
  1529. if (!params.m_comparisonTypeList.empty() && !assetListComparison.SetComparisonType(index, params.m_comparisonTypeList[0]))
  1530. {
  1531. return false;
  1532. }
  1533. if (!params.m_filePatternTypeList.empty() && !assetListComparison.SetFilePatternType(index, params.m_filePatternTypeList[0]))
  1534. {
  1535. return false;
  1536. }
  1537. if (!params.m_filePatternList.empty() && !assetListComparison.SetFilePattern(index, params.m_filePatternList[0]))
  1538. {
  1539. return false;
  1540. }
  1541. if (!params.m_tokenNamesList.empty() && !assetListComparison.SetOutput(index, params.m_tokenNamesList[0]))
  1542. {
  1543. return false;
  1544. }
  1545. if (!params.m_firstInputList.empty() && !assetListComparison.SetFirstInput(index, params.m_firstInputList[0]))
  1546. {
  1547. return false;
  1548. }
  1549. if (!params.m_secondInputList.empty() && !assetListComparison.SetSecondInput(index, params.m_secondInputList[0]))
  1550. {
  1551. return false;
  1552. }
  1553. return true;
  1554. }
  1555. void ApplicationManager::PrintComparisonRules(const AzToolsFramework::AssetFileInfoListComparison& assetListComparison, const AZStd::string& comparisonRulesAbsoluteFilePath)
  1556. {
  1557. AZ_Printf(AppWindowName, "\nContents of: %s\n\n", comparisonRulesAbsoluteFilePath.c_str());
  1558. const char* inputVariableMessage = "[input at runtime]";
  1559. int lineNum = 0;
  1560. for (const auto& comparisonData : assetListComparison.GetComparisonList())
  1561. {
  1562. const char* comparisonTypeName = AzToolsFramework::AssetFileInfoListComparison::ComparisonTypeNames[aznumeric_cast<AZ::u8>(comparisonData.m_comparisonType)];
  1563. AZ_Printf(AppWindowName, "%-10i %-15s (%s", lineNum, comparisonTypeName, comparisonData.m_firstInput.empty() ? inputVariableMessage : comparisonData.m_firstInput.c_str());
  1564. if (comparisonData.m_filePatternType != AzToolsFramework::AssetFileInfoListComparison::FilePatternType::Default)
  1565. {
  1566. AZ_Printf(AppWindowName, ")\n");
  1567. const char* filePatternTypeName = AzToolsFramework::AssetFileInfoListComparison::FilePatternTypeNames[aznumeric_cast<AZ::u8>(comparisonData.m_filePatternType)];
  1568. AZ_Printf(AppWindowName, "%-14s %s \"%s\"\n", "", filePatternTypeName, comparisonData.m_filePattern.c_str());
  1569. }
  1570. else
  1571. {
  1572. AZ_Printf(AppWindowName, ", %s )\n", comparisonData.m_secondInput.empty() ? inputVariableMessage : comparisonData.m_secondInput.c_str());
  1573. }
  1574. AZ_Printf(AppWindowName, "%-14s Output Token: %s\n", "", comparisonData.m_output.empty() ? "[No Token Set]" : comparisonData.m_output.c_str());
  1575. ++lineNum;
  1576. }
  1577. AZ_Printf(AppWindowName, "\n");
  1578. }
  1579. bool ApplicationManager::IsDefaultToken(const AZStd::string& pathOrToken)
  1580. {
  1581. return pathOrToken.size() == 1 && pathOrToken.at(0) == compareVariablePrefix;
  1582. }
  1583. bool ApplicationManager::RunCompareCommand(const AZ::Outcome<ComparisonParams, AZStd::string>& paramsOutcome)
  1584. {
  1585. using namespace AzToolsFramework;
  1586. if (!paramsOutcome.IsSuccess())
  1587. {
  1588. AZ_Error(AppWindowName, false, paramsOutcome.GetError().c_str());
  1589. return false;
  1590. }
  1591. AssetFileInfoListComparison rulesFileComparisonOperations;
  1592. // Load comparison rules from file if one was provided
  1593. if (!paramsOutcome.GetValue().m_comparisonRulesFile.AbsolutePath().empty())
  1594. {
  1595. auto rulesFileLoadResult = AssetFileInfoListComparison::Load(paramsOutcome.GetValue().m_comparisonRulesFile.AbsolutePath());
  1596. if (!rulesFileLoadResult.IsSuccess())
  1597. {
  1598. AZ_Error(AppWindowName, false, rulesFileLoadResult.GetError().c_str());
  1599. return false;
  1600. }
  1601. rulesFileComparisonOperations = rulesFileLoadResult.GetValue();
  1602. }
  1603. bool hasError = false;
  1604. for (AZStd::string platformName : AzFramework::PlatformHelper::GetPlatformsInterpreted(paramsOutcome.GetValue().m_platformFlags))
  1605. {
  1606. AZ_TracePrintf(AssetBundler::AppWindowName, "Running Compare command for the %s platform...\n", platformName.c_str());
  1607. ComparisonParams params = paramsOutcome.GetValue();
  1608. AddPlatformToAllComparisonParams(params, platformName);
  1609. AssetFileInfoListComparison comparisonOperations = rulesFileComparisonOperations;
  1610. // generate comparisons from additional commands and add it to comparisonOperations
  1611. ConvertRulesParamsToComparisonData(params.m_comparisonRulesParams, comparisonOperations, comparisonOperations.GetNumComparisonSteps());
  1612. if (params.m_comparisonRulesParams.m_intersectionCount)
  1613. {
  1614. if ((comparisonOperations.GetComparisonList().size() == 1) && comparisonOperations.GetComparisonList()[0].m_comparisonType != AssetFileInfoListComparison::ComparisonType::IntersectionCount)
  1615. {
  1616. AZ_Error(AppWindowName, false, "Invalid arguement detected. Command ( --%s ) is incompatible with compare operation of type (%s).",
  1617. IntersectionCountArg, AssetFileInfoListComparison::ComparisonTypeNames[aznumeric_cast<AZ::u8>(comparisonOperations.GetComparisonList()[0].m_comparisonType)]);
  1618. return false;
  1619. }
  1620. // Since IntersectionCount Operation cannot be combined with other operation Comparison List should be 1
  1621. else if (comparisonOperations.GetComparisonList().size() > 1)
  1622. {
  1623. AZ_Error(AppWindowName, false, "Compare operation of type ( %s ) cannot be combined with other comparison operations. Number of comparison operation detected (%d).",
  1624. AssetFileInfoListComparison::ComparisonTypeNames[aznumeric_cast<AZ::u8>(AssetFileInfoListComparison::ComparisonType::IntersectionCount)], comparisonOperations.GetComparisonList().size());
  1625. return false;
  1626. }
  1627. if (params.m_outputs.size())
  1628. {
  1629. comparisonOperations.SetOutput(0, params.m_outputs[0]);
  1630. }
  1631. }
  1632. else
  1633. {
  1634. //Store input and output values alongside the Comparison Steps they relate to
  1635. size_t secondInputIdx = 0;
  1636. for (size_t idx = 0; idx < comparisonOperations.GetComparisonList().size(); ++idx)
  1637. {
  1638. if (idx >= params.m_firstCompareFile.size())
  1639. {
  1640. AZ_Error(AppWindowName, false,
  1641. "Invalid command: The number of \"--%s\" inputs ( %i ) must match the number of Comparison Steps ( %i ).",
  1642. CompareFirstFileArg, params.m_firstCompareFile.size(), comparisonOperations.GetComparisonList().size());
  1643. return false;
  1644. }
  1645. // Set the first input
  1646. if (!IsDefaultToken(params.m_firstCompareFile.at(idx)))
  1647. {
  1648. comparisonOperations.SetFirstInput(idx, params.m_firstCompareFile.at(idx));
  1649. }
  1650. // Set the second input (if needed)
  1651. if (comparisonOperations.GetComparisonList().at(idx).m_comparisonType != AssetFileInfoListComparison::ComparisonType::FilePattern)
  1652. {
  1653. if (secondInputIdx >= params.m_secondCompareFile.size())
  1654. {
  1655. AZ_Error(AppWindowName, false,
  1656. "Invalid command: The number of \"--%s\" inputs ( %i ) must match the number of Comparison Steps that take two inputs.",
  1657. CompareSecondFileArg, params.m_secondCompareFile.size());
  1658. return false;
  1659. }
  1660. if (!IsDefaultToken(params.m_secondCompareFile.at(secondInputIdx)))
  1661. {
  1662. comparisonOperations.SetSecondInput(idx, params.m_secondCompareFile.at(secondInputIdx));
  1663. }
  1664. ++secondInputIdx;
  1665. }
  1666. // Set the output
  1667. if (idx >= params.m_outputs.size())
  1668. {
  1669. AZ_Error(AppWindowName, false,
  1670. "Invalid command: The number of \"--%s\" values ( %i ) must match the number of Comparison Steps ( %i ).",
  1671. CompareOutputFileArg, params.m_outputs.size(), comparisonOperations.GetComparisonList().size());
  1672. return false;
  1673. }
  1674. if (!IsDefaultToken(params.m_outputs.at(idx)))
  1675. {
  1676. comparisonOperations.SetOutput(idx, params.m_outputs.at(idx));
  1677. }
  1678. }
  1679. }
  1680. AZ::Outcome<AssetFileInfoList, AZStd::string> compareOutcome = comparisonOperations.Compare(params.m_firstCompareFile);
  1681. if (!compareOutcome.IsSuccess())
  1682. {
  1683. AZ_Error(AppWindowName, false, compareOutcome.GetError().c_str());
  1684. hasError = true;
  1685. continue;
  1686. }
  1687. if (params.m_printLast)
  1688. {
  1689. PrintComparisonAssetList(compareOutcome.GetValue(), params.m_outputs.size() ? params.m_outputs.back() : "");
  1690. }
  1691. // Check if we are performing a destructive overwrite that the user did not approve
  1692. if (!params.m_allowOverwrites)
  1693. {
  1694. AZStd::vector<AZStd::string> destructiveOverwriteFilePaths = comparisonOperations.GetDestructiveOverwriteFilePaths();
  1695. if (!destructiveOverwriteFilePaths.empty())
  1696. {
  1697. #if defined(AZ_ENABLE_TRACING)
  1698. for (const AZStd::string& path : destructiveOverwriteFilePaths)
  1699. {
  1700. AZ_Error(AssetBundler::AppWindowName, false, "Asset List file ( %s ) already exists, running this command would perform a destructive overwrite.", path.c_str());
  1701. }
  1702. #endif
  1703. AZ_Printf(AssetBundler::AppWindowName, "\nRun your command again with the ( --%s ) arg if you want to save over the existing file.\n\n", AllowOverwritesFlag)
  1704. hasError = true;
  1705. continue;
  1706. }
  1707. }
  1708. AZ_Printf(AssetBundler::AppWindowName, "Saving results of comparison operation...\n");
  1709. auto saveOutcome = comparisonOperations.SaveResults();
  1710. if (!saveOutcome.IsSuccess())
  1711. {
  1712. AZ_Error(AppWindowName, false, saveOutcome.GetError().c_str());
  1713. hasError = true;
  1714. continue;
  1715. }
  1716. AZ_Printf(AssetBundler::AppWindowName, "Save successful!\n");
  1717. for (const AZStd::string& comparisonKey : params.m_printComparisons)
  1718. {
  1719. PrintComparisonAssetList(comparisonOperations.GetComparisonResults(comparisonKey), comparisonKey);
  1720. }
  1721. }
  1722. return !hasError;
  1723. }
  1724. void ApplicationManager::AddPlatformToAllComparisonParams(ComparisonParams& params, const AZStd::string& platformName)
  1725. {
  1726. for (size_t i = 0; i < params.m_firstCompareFile.size(); ++i)
  1727. {
  1728. AddPlatformToComparisonParam(params.m_firstCompareFile[i], platformName);
  1729. }
  1730. for (size_t i = 0; i < params.m_secondCompareFile.size(); ++i)
  1731. {
  1732. AddPlatformToComparisonParam(params.m_secondCompareFile[i], platformName);
  1733. }
  1734. for (size_t i = 0; i < params.m_outputs.size(); ++i)
  1735. {
  1736. AddPlatformToComparisonParam(params.m_outputs[i], platformName);
  1737. }
  1738. }
  1739. void ApplicationManager::AddPlatformToComparisonParam(AZStd::string& inOut, const AZStd::string& platformName)
  1740. {
  1741. // Tokens don't have platforms
  1742. if (AzToolsFramework::AssetFileInfoListComparison::IsTokenFile(inOut))
  1743. {
  1744. return;
  1745. }
  1746. AzToolsFramework::RemovePlatformIdentifier(inOut);
  1747. FilePath tempPath(inOut, platformName);
  1748. inOut = tempPath.AbsolutePath();
  1749. }
  1750. void ApplicationManager::PrintComparisonAssetList(const AzToolsFramework::AssetFileInfoList& infoList, const AZStd::string& resultName)
  1751. {
  1752. using namespace AzToolsFramework;
  1753. if (infoList.m_fileInfoList.size() == 0)
  1754. {
  1755. return;
  1756. }
  1757. AZ_Printf(AssetBundler::AppWindowName, "Printing assets from the comparison result %s.\n", resultName.c_str());
  1758. AZ_Printf(AssetBundler::AppWindowName, "------------------------------------------\n");
  1759. for (const AssetFileInfo& assetFilenfo : infoList.m_fileInfoList)
  1760. {
  1761. AZ_Printf(AssetBundler::AppWindowName, "- %s\n", assetFilenfo.m_assetRelativePath.c_str());
  1762. }
  1763. AZ_Printf(AssetBundler::AppWindowName, "Total number of assets (%u).\n", infoList.m_fileInfoList.size());
  1764. AZ_Printf(AssetBundler::AppWindowName, "---------------------------\n");
  1765. }
  1766. bool ApplicationManager::RunBundleSettingsCommands(const AZ::Outcome<BundleSettingsParams, AZStd::string>& paramsOutcome)
  1767. {
  1768. using namespace AzToolsFramework;
  1769. if (!paramsOutcome.IsSuccess())
  1770. {
  1771. AZ_Error(AppWindowName, false, paramsOutcome.GetError().c_str());
  1772. return false;
  1773. }
  1774. BundleSettingsParams params = paramsOutcome.GetValue();
  1775. for (AZStd::string_view platformName : AzFramework::PlatformHelper::GetPlatformsInterpreted(params.m_platformFlags))
  1776. {
  1777. AssetBundleSettings bundleSettings;
  1778. // Attempt to load Bundle Settings file. If the load operation fails, we are making a new file and there is no need to error.
  1779. FilePath platformSpecificBundleSettingsFilePath = FilePath(params.m_bundleSettingsFile.AbsolutePath(), platformName);
  1780. AZ::Outcome<AssetBundleSettings, AZStd::string> loadBundleSettingsOutcome = AssetBundleSettings::Load(platformSpecificBundleSettingsFilePath.AbsolutePath());
  1781. if (loadBundleSettingsOutcome.IsSuccess())
  1782. {
  1783. bundleSettings = loadBundleSettingsOutcome.TakeValue();
  1784. }
  1785. // Asset List File
  1786. AZStd::string assetListFilePath = FilePath(params.m_assetListFile.AbsolutePath(), platformName).AbsolutePath();
  1787. if (!assetListFilePath.empty())
  1788. {
  1789. if (!AZ::StringFunc::EndsWith(assetListFilePath, AssetSeedManager::GetAssetListFileExtension()))
  1790. {
  1791. AZ_Error(AppWindowName, false, "Cannot set Asset List file to ( %s ): file extension must be ( %s ).", assetListFilePath.c_str(), AssetSeedManager::GetAssetListFileExtension());
  1792. return false;
  1793. }
  1794. if (!AZ::IO::FileIOBase::GetInstance()->Exists(assetListFilePath.c_str()))
  1795. {
  1796. AZ_Error(AppWindowName, false, "Cannot set Asset List file to ( %s ): file does not exist.", assetListFilePath.c_str());
  1797. return false;
  1798. }
  1799. // Make the path relative to the engine root folder before saving
  1800. AZ::StringFunc::Replace(assetListFilePath, GetEngineRoot(), "");
  1801. bundleSettings.m_assetFileInfoListPath = assetListFilePath;
  1802. }
  1803. // Output Bundle Path
  1804. AZStd::string outputBundlePath = FilePath(params.m_outputBundlePath.AbsolutePath(), platformName).AbsolutePath();
  1805. if (!outputBundlePath.empty())
  1806. {
  1807. if (!AZ::StringFunc::EndsWith(outputBundlePath, AssetBundleSettings::GetBundleFileExtension()))
  1808. {
  1809. AZ_Error(AppWindowName, false, "Cannot set Output Bundle Path to ( %s ): file extension must be ( %s ).", outputBundlePath.c_str(), AssetBundleSettings::GetBundleFileExtension());
  1810. return false;
  1811. }
  1812. // Make the path relative to the engine root folder before saving
  1813. AZ::StringFunc::Replace(outputBundlePath, GetEngineRoot(), "");
  1814. bundleSettings.m_bundleFilePath = outputBundlePath;
  1815. }
  1816. // Bundle Version
  1817. if (params.m_bundleVersion > 0 && params.m_bundleVersion <= AzFramework::AssetBundleManifest::CurrentBundleVersion)
  1818. {
  1819. bundleSettings.m_bundleVersion = params.m_bundleVersion;
  1820. }
  1821. // Max Bundle Size (in MB)
  1822. if (params.m_maxBundleSizeInMB > 0 && params.m_maxBundleSizeInMB <= AssetBundleSettings::GetMaxBundleSizeInMB())
  1823. {
  1824. bundleSettings.m_maxBundleSizeInMB = params.m_maxBundleSizeInMB;
  1825. }
  1826. // Print
  1827. if (params.m_print)
  1828. {
  1829. AZ_TracePrintf(AssetBundler::AppWindowName, "\nContents of Bundle Settings file ( %s ):\n", platformSpecificBundleSettingsFilePath.AbsolutePath().c_str());
  1830. AZ_TracePrintf(AssetBundler::AppWindowName, " Platform: %.*s\n", aznumeric_cast<int>(platformName.size()), platformName.data());
  1831. AZ_TracePrintf(AssetBundler::AppWindowName, " Asset List file: %s\n", bundleSettings.m_assetFileInfoListPath.c_str());
  1832. AZ_TracePrintf(AssetBundler::AppWindowName, " Output Bundle path: %s\n", bundleSettings.m_bundleFilePath.c_str());
  1833. AZ_TracePrintf(AssetBundler::AppWindowName, " Bundle Version: %i\n", bundleSettings.m_bundleVersion);
  1834. AZ_TracePrintf(AssetBundler::AppWindowName, " Max Bundle Size: %u MB\n\n", bundleSettings.m_maxBundleSizeInMB);
  1835. }
  1836. // Save
  1837. AZ_TracePrintf(AssetBundler::AppWindowName, "Saving Bundle Settings file to ( %s )...\n", platformSpecificBundleSettingsFilePath.AbsolutePath().c_str());
  1838. if (!AssetBundleSettings::Save(bundleSettings, platformSpecificBundleSettingsFilePath.AbsolutePath()))
  1839. {
  1840. AZ_Error(AssetBundler::AppWindowName, false, "Unable to save Bundle Settings file to ( %s ).", platformSpecificBundleSettingsFilePath.AbsolutePath().c_str());
  1841. return false;
  1842. }
  1843. AZ_TracePrintf(AssetBundler::AppWindowName, "Save successful!\n");
  1844. }
  1845. return true;
  1846. }
  1847. bool ApplicationManager::RunBundlesCommands(const AZ::Outcome<BundlesParamsList, AZStd::string>& paramsOutcome)
  1848. {
  1849. using namespace AzToolsFramework;
  1850. if (!paramsOutcome.IsSuccess())
  1851. {
  1852. AZ_Error(AppWindowName, false, paramsOutcome.GetError().c_str());
  1853. return false;
  1854. }
  1855. BundlesParamsList paramsList = paramsOutcome.GetValue();
  1856. AZStd::vector<AZStd::pair<AssetBundleSettings, BundlesParams>> allBundleSettings;
  1857. for (BundlesParams& params : paramsList)
  1858. {
  1859. // If no platform was input we want to loop over all possible platforms and make bundles for whatever we find
  1860. if (params.m_platformFlags == AzFramework::PlatformFlags::Platform_NONE)
  1861. {
  1862. params.m_platformFlags = AzFramework::PlatformFlags::AllNamedPlatforms;
  1863. }
  1864. // Load or generate Bundle Settings
  1865. AzFramework::PlatformFlags allPlatformsInBundle = AzFramework::PlatformFlags::Platform_NONE;
  1866. if (params.m_bundleSettingsFile.AbsolutePath().empty())
  1867. {
  1868. // Verify input file path formats before looking for platform-specific versions
  1869. auto fileExtensionOutcome = AssetFileInfoList::ValidateAssetListFileExtension(params.m_assetListFile.AbsolutePath());
  1870. if (!fileExtensionOutcome.IsSuccess())
  1871. {
  1872. AZ_Error(AssetBundler::AppWindowName, false, fileExtensionOutcome.GetError().c_str());
  1873. return false;
  1874. }
  1875. if (!AZ::IO::FileIOBase::GetInstance()->Exists(params.m_assetListFile.AbsolutePath().c_str()))
  1876. {
  1877. AZ_Error(
  1878. AppWindowName,
  1879. false,
  1880. "Cannot load Asset List file ( %.*s ): File does not exist.\n",
  1881. AZ_STRING_ARG(params.m_assetListFile.AbsolutePath()));
  1882. return false;
  1883. }
  1884. AZStd::vector<FilePath> allAssetListFilePaths = GetAllPlatformSpecificFilesOnDisk(params.m_assetListFile, params.m_platformFlags);
  1885. // Create temporary Bundle Settings structs for every Asset List file
  1886. for (const auto& assetListFilePath : allAssetListFilePaths)
  1887. {
  1888. AssetBundleSettings bundleSettings;
  1889. bundleSettings.m_assetFileInfoListPath = assetListFilePath.AbsolutePath();
  1890. bundleSettings.m_platform = GetPlatformIdentifier(assetListFilePath.AbsolutePath());
  1891. allPlatformsInBundle |= AzFramework::PlatformHelper::GetPlatformFlag(bundleSettings.m_platform);
  1892. allBundleSettings.emplace_back(AZStd::make_pair(bundleSettings, params));
  1893. }
  1894. }
  1895. else
  1896. {
  1897. // Verify input file path formats before looking for platform-specific versions
  1898. auto fileExtensionOutcome = AssetBundleSettings::ValidateBundleSettingsFileExtension(params.m_bundleSettingsFile.AbsolutePath());
  1899. if (!fileExtensionOutcome.IsSuccess())
  1900. {
  1901. AZ_Error(AssetBundler::AppWindowName, false, fileExtensionOutcome.GetError().c_str());
  1902. return false;
  1903. }
  1904. AZStd::vector<FilePath> allBundleSettingsFilePaths = GetAllPlatformSpecificFilesOnDisk(params.m_bundleSettingsFile, params.m_platformFlags);
  1905. // Attempt to load all Bundle Settings files (there may be one or many to load)
  1906. for (const auto& bundleSettingsFilePath : allBundleSettingsFilePaths)
  1907. {
  1908. AZ::Outcome<AssetBundleSettings, AZStd::string> loadBundleSettingsOutcome = AssetBundleSettings::Load(bundleSettingsFilePath.AbsolutePath());
  1909. if (!loadBundleSettingsOutcome.IsSuccess())
  1910. {
  1911. AZ_Error(AssetBundler::AppWindowName, false, loadBundleSettingsOutcome.GetError().c_str());
  1912. return false;
  1913. }
  1914. allBundleSettings.emplace_back(AZStd::make_pair(loadBundleSettingsOutcome.TakeValue(), params));
  1915. allPlatformsInBundle |= AzFramework::PlatformHelper::GetPlatformFlag(allBundleSettings.back().first.m_platform);
  1916. }
  1917. }
  1918. }
  1919. AZStd::atomic_uint failureCount = 0;
  1920. // Create all Bundles
  1921. AZ::parallel_for_each(allBundleSettings.begin(), allBundleSettings.end(), [this, &failureCount](AZStd::pair<AzToolsFramework::AssetBundleSettings, BundlesParams> bundleSettings)
  1922. {
  1923. BundlesParams params = bundleSettings.second;
  1924. auto overrideOutcome = ApplyBundleSettingsOverrides(
  1925. bundleSettings.first,
  1926. params.m_assetListFile.AbsolutePath(),
  1927. params.m_outputBundlePath.AbsolutePath(),
  1928. params.m_bundleVersion,
  1929. params.m_maxBundleSizeInMB);
  1930. if (!overrideOutcome.IsSuccess())
  1931. {
  1932. // Metric event has already been sent
  1933. AZ_Error(AppWindowName, false, overrideOutcome.GetError().c_str());
  1934. failureCount.fetch_add(1, AZStd::memory_order_relaxed);
  1935. return;
  1936. }
  1937. FilePath bundleFilePath(bundleSettings.first.m_bundleFilePath);
  1938. // Check if we are performing a destructive overwrite that the user did not approve
  1939. if (!params.m_allowOverwrites && AZ::IO::FileIOBase::GetInstance()->Exists(bundleFilePath.AbsolutePath().c_str()))
  1940. {
  1941. AZ_Error(AssetBundler::AppWindowName, false, "Bundle ( %s ) already exists, running this command would perform a destructive overwrite.\n\n"
  1942. "Run your command again with the ( --%s ) arg if you want to save over the existing file.", bundleFilePath.AbsolutePath().c_str(), AllowOverwritesFlag);
  1943. failureCount.fetch_add(1, AZStd::memory_order_relaxed);
  1944. return;
  1945. }
  1946. AZ_TracePrintf(AssetBundler::AppWindowName, "Creating Bundle ( %s )...\n", bundleFilePath.AbsolutePath().c_str());
  1947. bool result = false;
  1948. AssetBundleCommandsBus::BroadcastResult(result, &AssetBundleCommandsBus::Events::CreateAssetBundle, bundleSettings.first);
  1949. if (!result)
  1950. {
  1951. AZ_Error(AssetBundler::AppWindowName, false, "Unable to create bundle, target Bundle file path is ( %s ).", bundleFilePath.AbsolutePath().c_str());
  1952. failureCount.fetch_add(1, AZStd::memory_order_relaxed);
  1953. return;
  1954. }
  1955. AZ_TracePrintf(AssetBundler::AppWindowName, "Bundle ( %s ) created successfully!\n", bundleFilePath.AbsolutePath().c_str());
  1956. });
  1957. return failureCount == 0;
  1958. }
  1959. bool ApplicationManager::RunBundleSeedCommands(const AZ::Outcome<BundleSeedParams, AZStd::string>& paramsOutcome)
  1960. {
  1961. using namespace AzToolsFramework;
  1962. if (!paramsOutcome.IsSuccess())
  1963. {
  1964. AZ_Error(AppWindowName, false, paramsOutcome.GetError().c_str());
  1965. return false;
  1966. }
  1967. BundleSeedParams params = paramsOutcome.GetValue();
  1968. // If no platform was input we want to loop over all possible platforms and make bundles for whatever we find
  1969. if (params.m_bundleParams.m_platformFlags == AzFramework::PlatformFlags::Platform_NONE)
  1970. {
  1971. params.m_bundleParams.m_platformFlags = AzFramework::PlatformFlags::AllNamedPlatforms;
  1972. }
  1973. AZStd::vector<AssetBundleSettings> allBundleSettings;
  1974. if (params.m_bundleParams.m_bundleSettingsFile.AbsolutePath().empty())
  1975. {
  1976. // if no bundle settings file was provided generate one for each platform, values will be overridden later
  1977. for (AZStd::string_view platformName : AzFramework::PlatformHelper::GetPlatformsInterpreted(params.m_bundleParams.m_platformFlags))
  1978. {
  1979. allBundleSettings.emplace_back();
  1980. allBundleSettings.back().m_platform = platformName;
  1981. }
  1982. }
  1983. else
  1984. {
  1985. // if a bundle settings file was provided use values from the file, leave the asset list file path behind since it will be ignored anyways
  1986. AZStd::vector<FilePath> allBundleSettingsFilePaths = GetAllPlatformSpecificFilesOnDisk(params.m_bundleParams.m_bundleSettingsFile, params.m_bundleParams.m_platformFlags);
  1987. // Attempt to load all Bundle Settings files (there may be one or many to load)
  1988. for (const auto& bundleSettingsFilePath : allBundleSettingsFilePaths)
  1989. {
  1990. AZ::Outcome<AssetBundleSettings, AZStd::string> loadBundleSettingsOutcome = AssetBundleSettings::Load(bundleSettingsFilePath.AbsolutePath());
  1991. if (!loadBundleSettingsOutcome.IsSuccess())
  1992. {
  1993. AZ_Error(AssetBundler::AppWindowName, false, loadBundleSettingsOutcome.GetError().c_str());
  1994. return false;
  1995. }
  1996. allBundleSettings.emplace_back(loadBundleSettingsOutcome.TakeValue());
  1997. }
  1998. }
  1999. // Create all Bundles
  2000. for (AssetBundleSettings& bundleSettings : allBundleSettings)
  2001. {
  2002. auto overrideOutcome = ApplyBundleSettingsOverrides(
  2003. bundleSettings,
  2004. params.m_bundleParams.m_assetListFile.AbsolutePath(),
  2005. params.m_bundleParams.m_outputBundlePath.AbsolutePath(),
  2006. params.m_bundleParams.m_bundleVersion,
  2007. params.m_bundleParams.m_maxBundleSizeInMB);
  2008. if (!overrideOutcome.IsSuccess())
  2009. {
  2010. // Metric event has already been sent
  2011. AZ_Error(AppWindowName, false, overrideOutcome.GetError().c_str());
  2012. return false;
  2013. }
  2014. if (!params.m_bundleParams.m_allowOverwrites && AZ::IO::FileIOBase::GetInstance()->Exists(bundleSettings.m_bundleFilePath.c_str()))
  2015. {
  2016. AZ_Error(AssetBundler::AppWindowName, false, "Bundle ( %s ) already exists, running this command would perform a destructive overwrite.\n\n"
  2017. "Run your command again with the ( --%s ) arg if you want to save over the existing file.", bundleSettings.m_bundleFilePath.c_str(), AllowOverwritesFlag);
  2018. return false;
  2019. }
  2020. AzFramework::PlatformFlags platformFlag = AzFramework::PlatformHelper::GetPlatformFlag(bundleSettings.m_platform);
  2021. AzFramework::PlatformId platformId = static_cast<AzFramework::PlatformId>(AzFramework::PlatformHelper::GetPlatformIndexFromName(bundleSettings.m_platform.c_str()));
  2022. for (const AZStd::string& assetPath : params.m_addSeedList)
  2023. {
  2024. m_assetSeedManager->AddSeedAsset(assetPath, platformFlag);
  2025. }
  2026. auto assetList = m_assetSeedManager->GetDependenciesInfo(platformId, {});
  2027. if (assetList.size() == 0)
  2028. {
  2029. AZ_TracePrintf(AssetBundler::AppWindowName, "Platform ( %s ) had no assets based on these seeds, skipping bundle generation.\n", bundleSettings.m_platform.c_str());
  2030. }
  2031. else
  2032. {
  2033. AssetFileInfoList assetFileInfoList;
  2034. // convert from AZ::Data::AssetInfo to AssetFileInfo for AssetBundleAPI call
  2035. for (const auto& asset : assetList)
  2036. {
  2037. AssetFileInfo assetInfo;
  2038. assetInfo.m_assetId = asset.m_assetId;
  2039. assetInfo.m_assetRelativePath = asset.m_relativePath;
  2040. assetFileInfoList.m_fileInfoList.emplace_back(assetInfo);
  2041. }
  2042. AZ_TracePrintf(AssetBundler::AppWindowName, "Creating Bundle ( %s )...\n", bundleSettings.m_bundleFilePath.c_str());
  2043. bool result = false;
  2044. AssetBundleCommandsBus::BroadcastResult(result, &AssetBundleCommandsBus::Events::CreateAssetBundleFromList, bundleSettings, assetFileInfoList);
  2045. if (!result)
  2046. {
  2047. AZ_Error(AssetBundler::AppWindowName, false, "Unable to create bundle, target Bundle file path is ( %s ).", bundleSettings.m_bundleFilePath.c_str());
  2048. return false;
  2049. }
  2050. AZ_TracePrintf(AssetBundler::AppWindowName, "Bundle ( %s ) created successfully!\n", bundleSettings.m_bundleFilePath.c_str());
  2051. }
  2052. }
  2053. return true;
  2054. }
  2055. AZ::Outcome<void, AZStd::string> ApplicationManager::InitAssetCatalog(AzFramework::PlatformFlags platforms, const AZStd::string& assetCatalogFile)
  2056. {
  2057. using namespace AzToolsFramework;
  2058. if (platforms == AzFramework::PlatformFlags::Platform_NONE)
  2059. {
  2060. return AZ::Failure(AZStd::string("Invalid platform.\n"));
  2061. }
  2062. for (const AzFramework::PlatformId& platformId : AzFramework::PlatformHelper::GetPlatformIndicesInterpreted(platforms))
  2063. {
  2064. AZStd::string platformSpecificAssetCatalogPath;
  2065. if (assetCatalogFile.empty())
  2066. {
  2067. AZ::StringFunc::Path::ConstructFull(
  2068. PlatformAddressedAssetCatalog::GetAssetRootForPlatform(platformId).c_str(),
  2069. AssetBundler::AssetCatalogFilename,
  2070. platformSpecificAssetCatalogPath);
  2071. }
  2072. else
  2073. {
  2074. platformSpecificAssetCatalogPath = assetCatalogFile;
  2075. }
  2076. AZ_TracePrintf(AssetBundler::AppWindowNameVerbose, "Loading asset catalog from ( %s ).\n", platformSpecificAssetCatalogPath.c_str());
  2077. bool success = false;
  2078. {
  2079. AzToolsFramework::AssetCatalog::PlatformAddressedAssetCatalogRequestBus::EventResult(success, platformId, &AzToolsFramework::AssetCatalog::PlatformAddressedAssetCatalogRequestBus::Events::LoadCatalog, platformSpecificAssetCatalogPath.c_str());
  2080. }
  2081. if (!success && !AzFramework::PlatformHelper::IsSpecialPlatform(platforms))
  2082. {
  2083. return AZ::Failure(AZStd::string::format("Failed to open asset catalog file ( %s ).", platformSpecificAssetCatalogPath.c_str()));
  2084. }
  2085. }
  2086. return AZ::Success();
  2087. }
  2088. AZ::Outcome<void, AZStd::string> ApplicationManager::LoadSeedListFile(const AZStd::string& seedListFileAbsolutePath, AzFramework::PlatformFlags platformFlags)
  2089. {
  2090. AZ::Outcome<void, AZStd::string> fileExtensionOutcome = AzToolsFramework::AssetSeedManager::ValidateSeedFileExtension(seedListFileAbsolutePath);
  2091. if (!fileExtensionOutcome.IsSuccess())
  2092. {
  2093. return fileExtensionOutcome;
  2094. }
  2095. bool seedListFileExists = AZ::IO::FileIOBase::GetInstance()->Exists(seedListFileAbsolutePath.c_str());
  2096. if (seedListFileExists)
  2097. {
  2098. AZ_TracePrintf(AssetBundler::AppWindowName, "Loading Seed List file ( %s ).\n", seedListFileAbsolutePath.c_str());
  2099. if (!IsGemSeedFilePathValid(GetEngineRoot(), seedListFileAbsolutePath, m_gemInfoList, platformFlags))
  2100. {
  2101. return AZ::Failure(AZStd::string::format(
  2102. "Invalid Seed List file ( %s ). This can happen if you add a seed file from a gem that is not enabled for the current project ( %s ).",
  2103. seedListFileAbsolutePath.c_str(),
  2104. m_currentProjectName.c_str()));
  2105. }
  2106. if (!m_assetSeedManager->Load(seedListFileAbsolutePath))
  2107. {
  2108. return AZ::Failure(AZStd::string::format("Failed to load Seed List file ( %s ).", seedListFileAbsolutePath.c_str()));
  2109. }
  2110. }
  2111. return AZ::Success();
  2112. }
  2113. void ApplicationManager::PrintSeedList(const AZStd::string& seedListFileAbsolutePath)
  2114. {
  2115. AZ_Printf(AppWindowName, "\nContents of ( %s ):\n\n", seedListFileAbsolutePath.c_str());
  2116. for (const AzFramework::SeedInfo& seed : m_assetSeedManager->GetAssetSeedList())
  2117. {
  2118. AZ_Printf(AppWindowName, "%-60s%s\n", seed.m_assetRelativePath.c_str(), m_assetSeedManager->GetReadablePlatformList(seed).c_str());
  2119. }
  2120. AZ_Printf(AppWindowName, "\n");
  2121. }
  2122. bool ApplicationManager::RunPlatformSpecificAssetListCommands(const AssetListsParams& params, AzFramework::PlatformFlags platformFlags)
  2123. {
  2124. using namespace AzToolsFramework;
  2125. auto platformIds = AzFramework::PlatformHelper::GetPlatformIndices(platformFlags);
  2126. auto platformIdsInterpreted = AzFramework::PlatformHelper::GetPlatformIndicesInterpreted(platformFlags);
  2127. // Add Seeds
  2128. for (const auto& platformId : platformIds)
  2129. {
  2130. AzFramework::PlatformFlags platformFlag = AzFramework::PlatformHelper::GetPlatformFlagFromPlatformIndex(platformId);
  2131. for (const AZStd::string& assetPath : params.m_addSeedList)
  2132. {
  2133. m_assetSeedManager->AddSeedAsset(assetPath, platformFlag);
  2134. }
  2135. }
  2136. AZStd::unordered_set<AZ::Data::AssetId> exclusionList;
  2137. AZStd::vector<AZStd::string> wildcardPatternExclusionList;
  2138. for (const AZStd::string& asset : params.m_skipList)
  2139. {
  2140. // Is input a wildcard pattern?
  2141. if (LooksLikeWildcardPattern(asset))
  2142. {
  2143. wildcardPatternExclusionList.emplace_back(asset);
  2144. continue;
  2145. }
  2146. // Is input a valid asset in the cache?
  2147. AZ::Data::AssetId assetId = m_assetSeedManager->GetAssetIdByPath(asset, platformFlags);
  2148. if (assetId.IsValid())
  2149. {
  2150. exclusionList.emplace(assetId);
  2151. }
  2152. }
  2153. // Print
  2154. bool printExistingFiles = false;
  2155. if (params.m_print)
  2156. {
  2157. printExistingFiles = !params.m_assetListFile.AbsolutePath().empty()
  2158. && params.m_seedListFiles.empty()
  2159. && params.m_addSeedList.empty()
  2160. && !params.m_addDefaultSeedListFiles;
  2161. PrintAssetLists(params, platformIdsInterpreted, printExistingFiles, exclusionList, wildcardPatternExclusionList);
  2162. }
  2163. // Dry Run
  2164. if (params.m_dryRun || params.m_assetListFile.AbsolutePath().empty() || printExistingFiles)
  2165. {
  2166. return true;
  2167. }
  2168. AZ_Printf(AssetBundler::AppWindowName, "\n");
  2169. AZStd::atomic_uint failureCount = 0;
  2170. // Save
  2171. AZ::parallel_for_each(platformIdsInterpreted.begin(), platformIdsInterpreted.end(), [this, &params, &failureCount, &exclusionList, &wildcardPatternExclusionList](AzFramework::PlatformId platformId)
  2172. {
  2173. AzFramework::PlatformFlags platformFlag = AzFramework::PlatformHelper::GetPlatformFlagFromPlatformIndex(platformId);
  2174. FilePath platformSpecificAssetListFilePath = FilePath(params.m_assetListFile.AbsolutePath(), AzFramework::PlatformHelper::GetPlatformName(platformId));
  2175. AZStd::string assetListFileAbsolutePath = platformSpecificAssetListFilePath.AbsolutePath();
  2176. AZ_TracePrintf(AssetBundler::AppWindowName, "Saving Asset List file to ( %s )...\n", assetListFileAbsolutePath.c_str());
  2177. // Check if we are performing a destructive overwrite that the user did not approve
  2178. if (!params.m_allowOverwrites && AZ::IO::FileIOBase::GetInstance()->Exists(assetListFileAbsolutePath.c_str()))
  2179. {
  2180. AZ_Error(AssetBundler::AppWindowName, false, "Asset List file ( %s ) already exists, running this command would perform a destructive overwrite.\n\n"
  2181. "Run your command again with the ( --%s ) arg if you want to save over the existing file.\n", assetListFileAbsolutePath.c_str(), AllowOverwritesFlag);
  2182. failureCount.fetch_add(1, AZStd::memory_order_relaxed);
  2183. return;
  2184. }
  2185. // Generate Debug file
  2186. AZStd::string debugListFileAbsolutePath;
  2187. if (params.m_generateDebugFile)
  2188. {
  2189. debugListFileAbsolutePath = assetListFileAbsolutePath;
  2190. AZ::StringFunc::Path::ReplaceExtension(debugListFileAbsolutePath, AssetFileDebugInfoList::GetAssetListDebugFileExtension());
  2191. AZ_TracePrintf(AssetBundler::AppWindowName, "Saving Asset List Debug file to ( %s )...\n", debugListFileAbsolutePath.c_str());
  2192. }
  2193. if (!m_assetSeedManager->SaveAssetFileInfo(assetListFileAbsolutePath, platformFlag, exclusionList, debugListFileAbsolutePath, wildcardPatternExclusionList))
  2194. {
  2195. AZ_Error(AssetBundler::AppWindowName, false, "Unable to save Asset List file to ( %s ).\n", assetListFileAbsolutePath.c_str());
  2196. failureCount.fetch_add(1, AZStd::memory_order_relaxed);
  2197. return;
  2198. }
  2199. AZ_TracePrintf(AssetBundler::AppWindowName, "Save successful! ( %s )\n", assetListFileAbsolutePath.c_str());
  2200. });
  2201. return failureCount == 0;
  2202. }
  2203. void ApplicationManager::PrintAssetLists(const AssetListsParams& params, const AZStd::fixed_vector<AzFramework::PlatformId, AzFramework::PlatformId::NumPlatformIds>& platformIds,
  2204. bool printExistingFiles, const AZStd::unordered_set<AZ::Data::AssetId>& exclusionList, const AZStd::vector<AZStd::string>& wildcardPatternExclusionList)
  2205. {
  2206. using namespace AzToolsFramework;
  2207. // The user wants to print the contents of a pre-existing Asset List file *without* modifying it
  2208. if (printExistingFiles)
  2209. {
  2210. AZStd::vector<FilePath> allAssetListFiles = GetAllPlatformSpecificFilesOnDisk(params.m_assetListFile, params.m_platformFlags);
  2211. for (const FilePath& assetListFilePath : allAssetListFiles)
  2212. {
  2213. auto assetFileInfoOutcome = m_assetSeedManager->LoadAssetFileInfo(assetListFilePath.AbsolutePath());
  2214. if (!assetFileInfoOutcome.IsSuccess())
  2215. {
  2216. AZ_Error(AssetBundler::AppWindowName, false, assetFileInfoOutcome.GetError().c_str());
  2217. }
  2218. AZ_Printf(AssetBundler::AppWindowName, "\nPrinting contents of ( %s ):\n", assetListFilePath.AbsolutePath().c_str());
  2219. for (const AssetFileInfo& assetFileInfo : assetFileInfoOutcome.GetValue().m_fileInfoList)
  2220. {
  2221. AZ_Printf(AssetBundler::AppWindowName, "- %s\n", assetFileInfo.m_assetRelativePath.c_str());
  2222. }
  2223. AZ_Printf(AssetBundler::AppWindowName, "Total number of assets in ( %s ): %d\n", assetListFilePath.AbsolutePath().c_str(), assetFileInfoOutcome.GetValue().m_fileInfoList.size());
  2224. }
  2225. return;
  2226. }
  2227. // The user wants to print the contents of a recently-modified Asset List file
  2228. for (const AzFramework::PlatformId platformId : platformIds)
  2229. {
  2230. AssetSeedManager::AssetsInfoList assetsInfoList = m_assetSeedManager->GetDependenciesInfo(platformId, exclusionList, nullptr, wildcardPatternExclusionList);
  2231. AZ_Printf(AssetBundler::AppWindowName, "\nPrinting assets for Platform ( %s ):\n", AzFramework::PlatformHelper::GetPlatformName(platformId));
  2232. for (const AZ::Data::AssetInfo& assetInfo : assetsInfoList)
  2233. {
  2234. AZ_Printf(AssetBundler::AppWindowName, "- %s\n", assetInfo.m_relativePath.c_str());
  2235. }
  2236. AZ_Printf(AssetBundler::AppWindowName, "Total number of assets for Platform ( %s ): %d.\n", AzFramework::PlatformHelper::GetPlatformName(platformId), assetsInfoList.size());
  2237. }
  2238. }
  2239. AZStd::vector<FilePath> ApplicationManager::GetAllPlatformSpecificFilesOnDisk(const FilePath& platformIndependentFilePath, AzFramework::PlatformFlags platformFlags)
  2240. {
  2241. using namespace AzToolsFramework;
  2242. AZStd::vector<FilePath> platformSpecificPaths;
  2243. if (platformIndependentFilePath.AbsolutePath().empty())
  2244. {
  2245. return platformSpecificPaths;
  2246. }
  2247. FilePath testFilePath;
  2248. for (AZStd::string_view platformName : AzFramework::PlatformHelper::GetPlatformsInterpreted(platformFlags))
  2249. {
  2250. testFilePath = FilePath(platformIndependentFilePath.AbsolutePath(), platformName);
  2251. if (!testFilePath.AbsolutePath().empty() && AZ::IO::FileIOBase::GetInstance()->Exists(testFilePath.AbsolutePath().c_str()))
  2252. {
  2253. platformSpecificPaths.emplace_back(testFilePath.AbsolutePath());
  2254. }
  2255. }
  2256. return platformSpecificPaths;
  2257. }
  2258. AZ::Outcome<void, AZStd::string> ApplicationManager::ApplyBundleSettingsOverrides(
  2259. AzToolsFramework::AssetBundleSettings& bundleSettings,
  2260. const AZStd::string& assetListFilePath,
  2261. const AZStd::string& outputBundleFilePath,
  2262. int bundleVersion,
  2263. int maxBundleSize)
  2264. {
  2265. using namespace AzToolsFramework;
  2266. // Asset List file path
  2267. if (!assetListFilePath.empty())
  2268. {
  2269. FilePath platformSpecificPath = FilePath(assetListFilePath, bundleSettings.m_platform);
  2270. if (platformSpecificPath.AbsolutePath().empty())
  2271. {
  2272. return AZ::Failure(AZStd::string::format(
  2273. "Failed to apply Bundle Settings overrides: ( %s ) is incompatible with input Bundle Settings file.",
  2274. assetListFilePath.c_str()));
  2275. }
  2276. bundleSettings.m_assetFileInfoListPath = platformSpecificPath.AbsolutePath();
  2277. }
  2278. // Output Bundle file path
  2279. if (!outputBundleFilePath.empty())
  2280. {
  2281. FilePath platformSpecificPath = FilePath(outputBundleFilePath, bundleSettings.m_platform);
  2282. if (platformSpecificPath.AbsolutePath().empty())
  2283. {
  2284. return AZ::Failure(AZStd::string::format(
  2285. "Failed to apply Bundle Settings overrides: ( %s ) is incompatible with input Bundle Settings file.",
  2286. outputBundleFilePath.c_str()));
  2287. }
  2288. bundleSettings.m_bundleFilePath = platformSpecificPath.AbsolutePath();
  2289. }
  2290. // Bundle Version
  2291. if (bundleVersion > 0 && bundleVersion <= AzFramework::AssetBundleManifest::CurrentBundleVersion)
  2292. {
  2293. bundleSettings.m_bundleVersion = bundleVersion;
  2294. }
  2295. // Max Bundle Size
  2296. if (maxBundleSize > 0 && maxBundleSize <= AssetBundleSettings::GetMaxBundleSizeInMB())
  2297. {
  2298. bundleSettings.m_maxBundleSizeInMB = maxBundleSize;
  2299. }
  2300. return AZ::Success();
  2301. }
  2302. ////////////////////////////////////////////////////////////////////////////////////////////
  2303. // Output Help Text
  2304. ////////////////////////////////////////////////////////////////////////////////////////////
  2305. void ApplicationManager::OutputHelp(CommandType commandType)
  2306. {
  2307. using namespace AssetBundler;
  2308. AZ_Printf(AppWindowName, "This program can be used to create asset bundles that can be used by the runtime to load assets.\n");
  2309. AZ_Printf(AppWindowName, "--%-20s-Displays more detailed output messages.\n\n", VerboseFlag);
  2310. switch (commandType)
  2311. {
  2312. case CommandType::Seeds:
  2313. OutputHelpSeeds();
  2314. break;
  2315. case CommandType::AssetLists:
  2316. OutputHelpAssetLists();
  2317. break;
  2318. case CommandType::ComparisonRules:
  2319. OutputHelpComparisonRules();
  2320. break;
  2321. case CommandType::Compare:
  2322. OutputHelpCompare();
  2323. break;
  2324. case CommandType::BundleSettings:
  2325. OutputHelpBundleSettings();
  2326. break;
  2327. case CommandType::Bundles:
  2328. OutputHelpBundles();
  2329. break;
  2330. case CommandType::BundleSeed:
  2331. OutputHelpBundleSeed();
  2332. break;
  2333. case CommandType::Invalid:
  2334. AZ_Printf(AppWindowName, "Input to this command follows the format: [subCommandName] --exampleArgThatTakesInput exampleInput --exampleFlagThatTakesNoInput\n");
  2335. AZ_Printf(AppWindowName, " - Example: \"assetLists --assetListFile example.assetlist --addDefaultSeedListFiles --print\"\n");
  2336. AZ_Printf(AppWindowName, "\n");
  2337. AZ_Printf(AppWindowName, "Some args in this tool take paths as arguments, and there are two main types:\n");
  2338. AZ_Printf(AppWindowName, " \"path\" - This refers to an Engine-Root-Relative path.\n");
  2339. AZ_Printf(AppWindowName, " - Example: \"C:\\O3DE\\dev\\SamplesProject\\test.txt\" can be represented as \"SamplesProject\\test.txt\".\n");
  2340. AZ_Printf(AppWindowName, " \"cache path\" - This refers to a Cache-Relative path.\n");
  2341. AZ_Printf(AppWindowName, " - Example: \"C:\\O3DE\\dev\\Cache\\SamplesProject\\pc\\samplesproject\\animations\\skeletonlist.xml\" is represented as \"animations\\skeletonlist.xml\".\n");
  2342. AZ_Printf(AppWindowName, "\n");
  2343. OutputHelpSeeds();
  2344. OutputHelpAssetLists();
  2345. OutputHelpComparisonRules();
  2346. OutputHelpCompare();
  2347. OutputHelpBundleSettings();
  2348. OutputHelpBundles();
  2349. OutputHelpBundleSeed();
  2350. AZ_Printf(AppWindowName, "\n\nTo see less Help text, type in a Sub-Command before requesting the Help text. For example: \"%s --%s\".\n", SeedsCommand, HelpFlag);
  2351. break;
  2352. }
  2353. if (commandType != CommandType::Invalid)
  2354. {
  2355. AZ_Printf(AppWindowName, "\n\nTo see more Help text, type: \"--%s\" without any other input.\n", HelpFlag);
  2356. }
  2357. }
  2358. void ApplicationManager::OutputHelpSeeds()
  2359. {
  2360. using namespace AzToolsFramework;
  2361. AZ_Printf(AppWindowName, "\n%-25s-Subcommand for performing operations on Seed List files.\n", SeedsCommand);
  2362. AZ_Printf(AppWindowName, " --%-25s-[Required] Specifies the Seed List file to operate on by path. Must include (.%s) file extension.\n", SeedListFileArg, AssetSeedManager::GetSeedFileExtension());
  2363. AZ_Printf(AppWindowName, " --%-25s-Adds the asset to the list of root assets for the specified platform.\n", AddSeedArg);
  2364. AZ_Printf(AppWindowName, "%-31s---Takes in a cache path to a pre-processed asset.\n", "");
  2365. AZ_Printf(AppWindowName, " --%-25s-Removes the asset from the list of root assets for the specified platform.\n", RemoveSeedArg);
  2366. AZ_Printf(AppWindowName, "%-31s---To completely remove the asset, it must be removed for all platforms.\n", "");
  2367. AZ_Printf(AppWindowName, "%-31s---Takes in a cache path to a pre-processed asset. A cache path is a path relative to \"ProjectPath\\Cache\\platform\\\"\n", "");
  2368. AZ_Printf(AppWindowName, " --%-25s-Adds the specified platform to every Seed in the Seed List file, if possible.\n", AddPlatformToAllSeedsFlag);
  2369. AZ_Printf(AppWindowName, " --%-25s-Removes the specified platform from every Seed in the Seed List file, if possible.\n", RemovePlatformFromAllSeedsFlag);
  2370. AZ_Printf(AppWindowName, " --%-25s-Outputs the contents of the Seed List file after performing any specified operations.\n", PrintFlag);
  2371. AZ_Printf(AppWindowName, " --%-25s-Specifies the platform(s) referenced by all Seed operations.\n", PlatformArg);
  2372. AZ_Printf(AppWindowName, "%-31s---Requires an existing cache of assets for the input platform(s).\n", "");
  2373. AZ_Printf(AppWindowName, "%-31s---Defaults to all enabled platforms. Platforms can be changed by modifying AssetProcessorPlatformConfig.setreg.\n", "");
  2374. AZ_Printf(AppWindowName, " --%-25s-Updates the path hints stored in the Seed List file.\n", UpdateSeedPathArg);
  2375. AZ_Printf(AppWindowName, " --%-25s-Removes the path hints stored in the Seed List file.\n", RemoveSeedPathArg);
  2376. AZ_Printf(AppWindowName, " --%-25s-Allows input file path to still match if the file path case is different than on disk.\n", IgnoreFileCaseFlag);
  2377. AZ_Printf(AppWindowName, " --%-25s-[Testing] Specifies the Asset Catalog file referenced by all Seed operations.\n", AssetCatalogFileArg);
  2378. AZ_Printf(AppWindowName, "%-31s---Designed to be used in Unit Tests.\n", "");
  2379. AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootstrap.cfg's project_path.\n", ProjectArg);
  2380. }
  2381. void ApplicationManager::OutputHelpAssetLists()
  2382. {
  2383. using namespace AzToolsFramework;
  2384. AZ_Printf(AppWindowName, "\n%-25s-Subcommand for generating Asset List Files.\n", AssetListsCommand);
  2385. AZ_Printf(AppWindowName, " --%-25s-Specifies the Asset List file to operate on by path. Must include (.%s) file extension.\n", AssetListFileArg, AssetSeedManager::GetAssetListFileExtension());
  2386. AZ_Printf(AppWindowName, " --%-25s-Specifies the Seed List file(s) that will be used as root(s) when generating this Asset List file.\n", SeedListFileArg);
  2387. AZ_Printf(AppWindowName, " --%-25s-Specifies the Seed(s) to use as root(s) when generating this Asset List File.\n", AddSeedArg);
  2388. AZ_Printf(AppWindowName, "%-31s---Takes in a cache path to a pre-processed asset. A cache path is a path relative to \"ProjectPath\\Cache\\platform\\\"\n", "");
  2389. AZ_Printf(AppWindowName, " --%-25s-The specified files and all dependencies will be ignored when generating the Asset List file.\n", SkipArg);
  2390. AZ_Printf(AppWindowName, "%-31s---Takes in a comma-separated list of either: cache paths to pre-processed assets, or wildcard patterns.\n", "");
  2391. AZ_Printf(AppWindowName, " --%-25s-Automatically include all default Seed List files in generated Asset List File.\n", AddDefaultSeedListFilesFlag);
  2392. AZ_Printf(AppWindowName, "%-31s---This will include Seed List files for the Open 3D Engine Engine and all enabled Gems.\n", "");
  2393. AZ_Printf(AppWindowName, " --%-25s-Specifies the platform(s) to generate an Asset List file for.\n", PlatformArg);
  2394. AZ_Printf(AppWindowName, "%-31s---Requires an existing cache of assets for the input platform(s).\n", "");
  2395. AZ_Printf(AppWindowName, "%-31s---Defaults to all enabled platforms. Platforms can be changed by modifying AssetProcessorPlatformConfig.setreg.\n", "");
  2396. AZ_Printf(AppWindowName, " --%-25s-[Testing] Specifies the Asset Catalog file referenced by all Asset List operations.\n", AssetCatalogFileArg);
  2397. AZ_Printf(AppWindowName, "%-31s---Designed to be used in Unit Tests.\n", "");
  2398. AZ_Printf(AppWindowName, " --%-25s-Outputs the contents of the Asset List file after adding any specified seed files.\n", PrintFlag);
  2399. AZ_Printf(AppWindowName, " --%-25s-Run all input commands, without saving to the specified Asset List file.\n", DryRunFlag);
  2400. AZ_Printf(AppWindowName, " --%-25s-Generates a human-readable file that maps every entry in the Asset List file to the Seed that generated it.\n", GenerateDebugFileFlag);
  2401. AZ_Printf(AppWindowName, " --%-25s-Allow destructive overwrites of files. Include this arg in automation.\n", AllowOverwritesFlag);
  2402. AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootstrap.cfg's project_path.\n", ProjectArg);
  2403. }
  2404. void ApplicationManager::OutputHelpComparisonRules()
  2405. {
  2406. using namespace AzToolsFramework;
  2407. AZ_Printf(AppWindowName, "\n%-25s-Subcommand for generating Comparison Rules files.\n", ComparisonRulesCommand);
  2408. AZ_Printf(AppWindowName, " --%-25s-Specifies the Comparison Rules file to operate on by path.\n", ComparisonRulesFileArg);
  2409. AZ_Printf(AppWindowName, " --%-25s-Adds a Comparison Step to the given Comparison Rules file at the specified line number.\n", AddComparisonStepArg);
  2410. AZ_Printf(AppWindowName, "%-31s---Takes in a non-negative integer. If no input is supplied, the Comparison Step will be added to the end.\n", "");
  2411. AZ_Printf(AppWindowName, " --%-25s-Removes the Comparison Step present at the input line number from the given Comparison Rules file.\n", RemoveComparisonStepArg);
  2412. AZ_Printf(AppWindowName, " --%-25s-Moves a Comparison Step from one line number to another line number in the given Comparison Rules file.\n", MoveComparisonStepArg);
  2413. AZ_Printf(AppWindowName, "%-31s---Takes in a comma-separated pair of non-negative integers: the original line number and the destination line number.\n", "");
  2414. AZ_Printf(AppWindowName, " --%-25s-Edits the Comparison Step at the input line number using values from other input arguments.\n", EditComparisonStepArg);
  2415. AZ_Printf(AppWindowName, "%-31s---When editing, other input arguments may only contain one input value.\n", "");
  2416. AZ_Printf(AppWindowName, " --%-25s-A comma seperated list of Comparison types.\n", ComparisonTypeArg);
  2417. AZ_Printf(AppWindowName, "%-31s---Valid inputs: delta, union, intersection, complement, filepattern.\n", "");
  2418. AZ_Printf(AppWindowName, " --%-25s-A comma seperated list of file pattern matching types.\n", ComparisonFilePatternTypeArg);
  2419. AZ_Printf(AppWindowName, "%-31s---Valid inputs: wildcard, regex.\n", "");
  2420. AZ_Printf(AppWindowName, "%-31s---Must match the number of FilePattern comparisons specified in ( --%s ) argument list.\n", "", ComparisonTypeArg);
  2421. AZ_Printf(AppWindowName, " --%-25s-A comma seperated list of file patterns.\n", ComparisonFilePatternArg);
  2422. AZ_Printf(AppWindowName, "%-31s---Must match the number of FilePattern comparisons specified in ( --%s ) argument list.\n", "", ComparisonTypeArg);
  2423. AZ_Printf(AppWindowName, " --%-25s-A comma seperated list of output Token names.\n", ComparisonTokenNameArg);
  2424. AZ_Printf(AppWindowName, " --%-25s-The Token name of the Comparison Step you wish to use as the first input of this Comparison Step.\n", ComparisonFirstInputArg);
  2425. AZ_Printf(AppWindowName, " --%-25s-The Token name of the Comparison Step you wish to use as the second input of this Comparison Step.\n", ComparisonSecondInputArg);
  2426. AZ_Printf(AppWindowName, "%-31s---Comparison Steps of the ( FilePattern ) type only accept one input Token, and cannot be used with this arg.\n", "");
  2427. AZ_Printf(AppWindowName, " --%-25s-Outputs the contents of the Comparison Rules file after performing any specified operations.\n", PrintFlag);
  2428. AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootstrap.cfg's project_path.\n", ProjectArg);
  2429. }
  2430. void ApplicationManager::OutputHelpCompare()
  2431. {
  2432. using namespace AzToolsFramework;
  2433. AZ_Printf(AppWindowName, "\n%-25s-Subcommand for performing comparisons between asset list files.\n", CompareCommand);
  2434. AZ_Printf(AppWindowName, " --%-25s-Specifies the Comparison Rules file to load rules from.\n", ComparisonRulesFileArg);
  2435. AZ_Printf(AppWindowName, "%-31s---When entering input and output values, input the single '$' character to use the default values defined in the file.\n", "");
  2436. AZ_Printf(AppWindowName, "%-31s---All additional comparison rules specified in this command will be done after the comparison operations loaded from the rules file.\n", "");
  2437. AZ_Printf(AppWindowName, " --%-25s-A comma seperated list of comparison types.\n", ComparisonTypeArg);
  2438. AZ_Printf(AppWindowName, "%-31s---Valid inputs: delta, union, intersection, complement, filepattern, intersectioncount.\n", "");
  2439. AZ_Printf(AppWindowName, " --%-25s-A comma seperated list of file pattern matching types.\n", ComparisonFilePatternTypeArg);
  2440. AZ_Printf(AppWindowName, "%-31s---Valid inputs: wildcard, regex.\n", "");
  2441. AZ_Printf(AppWindowName, "%-31s---Must match the number of FilePattern comparisons specified in ( --%s ) argument list.\n", "", ComparisonTypeArg);
  2442. AZ_Printf(AppWindowName, " --%-25s-A comma seperated list of file patterns.\n", ComparisonFilePatternArg);
  2443. AZ_Printf(AppWindowName, "%-31s---Must match the number of FilePattern comparisons specified in ( --%s ) argument list.\n", "", ComparisonTypeArg);
  2444. AZ_Printf(AppWindowName, " --%-25s-Specifies the count that will be used during the %s compare operation.\n", IntersectionCountArg, AssetFileInfoListComparison::ComparisonTypeNames[aznumeric_cast<AZ::u8>(AssetFileInfoListComparison::ComparisonType::IntersectionCount)]);
  2445. AZ_Printf(AppWindowName, " --%-25s-A comma seperated list of first inputs for comparison.\n", CompareFirstFileArg);
  2446. AZ_Printf(AppWindowName, "%-31s---Must match the number of comparison operations.\n", "");
  2447. AZ_Printf(AppWindowName, " --%-25s-A comma seperated list of second inputs for comparison.\n", CompareSecondFileArg);
  2448. AZ_Printf(AppWindowName, "%-31s---Must match the number of comparison operations that require two inputs.\n", "");
  2449. AZ_Printf(AppWindowName, " --%-25s-A comma seperated list of outputs for the comparison command.\n", CompareOutputFileArg);
  2450. AZ_Printf(AppWindowName, "%-31s---Must match the number of comparison operations.\n", "");
  2451. AZ_Printf(AppWindowName, "%-31s---Inputs and outputs can be a file or a variable passed from another comparison.\n", "");
  2452. AZ_Printf(AppWindowName, "%-31s---Variables are specified by the prefix %c.\n", "", compareVariablePrefix);
  2453. AZ_Printf(AppWindowName, " --%-25s-A comma seperated list of paths or variables to print to console after comparison operations complete.\n", ComparePrintArg);
  2454. AZ_Printf(AppWindowName, "%-31s---Leave list blank to just print the final comparison result.\n", "");
  2455. AZ_Printf(AppWindowName, " --%-25s-Specifies the platform(s) referenced when determining which Asset List files to compare.\n", PlatformArg);
  2456. AZ_Printf(AppWindowName, "%-31s---All input Asset List files must exist for all specified platforms\n", "");
  2457. AZ_Printf(AppWindowName, "%-31s---Defaults to all enabled platforms. Platforms can be changed by modifying AssetProcessorPlatformConfig.setreg.\n", "");
  2458. AZ_Printf(AppWindowName, " --%-25s-Allow destructive overwrites of files. Include this arg in automation.\n", AllowOverwritesFlag);
  2459. AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootstrap.cfg's project_path.\n", ProjectArg);
  2460. }
  2461. void ApplicationManager::OutputHelpBundleSettings()
  2462. {
  2463. using namespace AzToolsFramework;
  2464. AZ_Printf(AppWindowName, "\n%-25s-Subcommand for performing operations on Bundle Settings files.\n", BundleSettingsCommand);
  2465. AZ_Printf(AppWindowName, " --%-25s-[Required] Specifies the Bundle Settings file to operate on by path. Must include (.%s) file extension.\n", BundleSettingsFileArg, AssetBundleSettings::GetBundleSettingsFileExtension());
  2466. AZ_Printf(AppWindowName, " --%-25s-Sets the Asset List file to use for Bundle generation. Must include (.%s) file extension.\n", AssetListFileArg, AssetSeedManager::GetAssetListFileExtension());
  2467. AZ_Printf(AppWindowName, " --%-25s-Sets the path where generated Bundles will be stored. Must include (.%s) file extension.\n", OutputBundlePathArg, AssetBundleSettings::GetBundleFileExtension());
  2468. AZ_Printf(AppWindowName, " --%-25s-Determines which version of Open 3D Engine Bundles to generate. Current version is (%i).\n", BundleVersionArg, AzFramework::AssetBundleManifest::CurrentBundleVersion);
  2469. AZ_Printf(AppWindowName, " --%-25s-Sets the maximum size for a single Bundle (in MB). Default size is (%i MB).\n", MaxBundleSizeArg, AssetBundleSettings::GetMaxBundleSizeInMB());
  2470. AZ_Printf(AppWindowName, "%-31s---Bundles larger than this limit will be divided into a series of smaller Bundles and named accordingly.\n", "");
  2471. AZ_Printf(AppWindowName, " --%-25s-Specifies the platform(s) referenced by all Bundle Settings operations.\n", PlatformArg);
  2472. AZ_Printf(AppWindowName, "%-31s---Defaults to all enabled platforms. Platforms can be changed by modifying AssetProcessorPlatformConfig.setreg.\n", "");
  2473. AZ_Printf(AppWindowName, " --%-25s-Outputs the contents of the Bundle Settings file after modifying any specified values.\n", PrintFlag);
  2474. AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootstrap.cfg's project_path.\n", ProjectArg);
  2475. }
  2476. void ApplicationManager::OutputHelpBundles()
  2477. {
  2478. using namespace AzToolsFramework;
  2479. AZ_Printf(AppWindowName, "\n%-25s-Subcommand for generating bundles. Must provide either (--%s) or (--%s and --%s).\n", BundlesCommand, BundleSettingsFileArg, AssetListFileArg, OutputBundlePathArg);
  2480. AZ_Printf(AppWindowName, " --%-25s-Specifies the Bundle Settings files to operate on by path. Must include (.%s) file extension.\n", BundleSettingsFileArg, AssetBundleSettings::GetBundleSettingsFileExtension());
  2481. AZ_Printf(AppWindowName, "%-31s---If any other args are specified, they will override the values stored inside this file.\n", "");
  2482. AZ_Printf(AppWindowName, " --%-25s-Sets the Asset List files to use for Bundle generation. Must include (.%s) file extension.\n", AssetListFileArg, AssetSeedManager::GetAssetListFileExtension());
  2483. AZ_Printf(AppWindowName, " --%-25s-Sets the paths where generated Bundles will be stored. Must include (.%s) file extension.\n", OutputBundlePathArg, AssetBundleSettings::GetBundleFileExtension());
  2484. AZ_Printf(AppWindowName, " --%-25s-Determines which versions of Open 3D Engine Bundles to generate. Current version is (%i).\n", BundleVersionArg, AzFramework::AssetBundleManifest::CurrentBundleVersion);
  2485. AZ_Printf(AppWindowName, " --%-25s-Sets the maximum size for Bundles (in MB). Default size is (%i MB).\n", MaxBundleSizeArg, AssetBundleSettings::GetMaxBundleSizeInMB());
  2486. AZ_Printf(AppWindowName, "%-31s---Bundles larger than this limit will be divided into a series of smaller Bundles and named accordingly.\n", "");
  2487. AZ_Printf(AppWindowName, " --%-25s-Specifies the platform(s) that will be referenced when generating Bundles.\n", PlatformArg);
  2488. AZ_Printf(AppWindowName, "%-31s---If no platforms are specified, Bundles will be generated for all available platforms.\n", "");
  2489. AZ_Printf(AppWindowName, " --%-25s-Allow destructive overwrites of files. Include this arg in automation.\n", AllowOverwritesFlag);
  2490. AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootstrap.cfg's project_path.\n", ProjectArg);
  2491. }
  2492. void ApplicationManager::OutputHelpBundleSeed()
  2493. {
  2494. using namespace AzToolsFramework;
  2495. AZ_Printf(AppWindowName, "\n%-25s-Subcommand for generating bundles directly from seeds. Must provide either (--%s) or (--%s).\n", BundleSeedCommand, BundleSettingsFileArg, OutputBundlePathArg);
  2496. AZ_Printf(AppWindowName, " --%-25s-Adds the asset to the list of root assets for the specified platform.\n", AddSeedArg);
  2497. AZ_Printf(AppWindowName, "%-31s---Takes in a cache path to a pre-processed asset. A cache path is a path relative to \"ProjectPath\\Cache\\platform\\\"\n", "");
  2498. AZ_Printf(AppWindowName, " --%-25s-Specifies the Bundle Settings file to operate on by path. Must include (.%s) file extension.\n", BundleSettingsFileArg, AssetBundleSettings::GetBundleSettingsFileExtension());
  2499. AZ_Printf(AppWindowName, " --%-25s-Sets the path where generated Bundles will be stored. Must include (.%s) file extension.\n", OutputBundlePathArg, AssetBundleSettings::GetBundleFileExtension());
  2500. AZ_Printf(AppWindowName, " --%-25s-Determines which version of Open 3D Engine Bundles to generate. Current version is (%i).\n", BundleVersionArg, AzFramework::AssetBundleManifest::CurrentBundleVersion);
  2501. AZ_Printf(AppWindowName, " --%-25s-Sets the maximum size for a single Bundle (in MB). Default size is (%i MB).\n", MaxBundleSizeArg, AssetBundleSettings::GetMaxBundleSizeInMB());
  2502. AZ_Printf(AppWindowName, "%-31s---Bundles larger than this limit will be divided into a series of smaller Bundles and named accordingly.\n", "");
  2503. AZ_Printf(AppWindowName, " --%-25s-Specifies the platform(s) that will be referenced when generating Bundles.\n", PlatformArg);
  2504. AZ_Printf(AppWindowName, "%-31s---If no platforms are specified, Bundles will be generated for all available platforms.\n", "");
  2505. AZ_Printf(AppWindowName, " --%-25s-Allow destructive overwrites of files. Include this arg in automation.\n", AllowOverwritesFlag);
  2506. AZ_Printf(AppWindowName, " --%-25s-[Testing] Specifies the Asset Catalog file referenced by all Bundle operations.\n", AssetCatalogFileArg);
  2507. AZ_Printf(AppWindowName, "%-31s---Designed to be used in Unit Tests.\n", "");
  2508. AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootstrap.cfg's project_path.\n", ProjectArg);
  2509. }
  2510. ////////////////////////////////////////////////////////////////////////////////////////////
  2511. // Formatting for Output Text
  2512. ////////////////////////////////////////////////////////////////////////////////////////////
  2513. bool ApplicationManager::OnPreError(const char* window, const char* fileName, int line, [[maybe_unused]] const char* func, const char* message)
  2514. {
  2515. printf("\n");
  2516. printf("[ERROR] - %s:\n", window);
  2517. if (m_showVerboseOutput)
  2518. {
  2519. printf("(%s - Line %i)\n", fileName, line);
  2520. }
  2521. printf("%s", message);
  2522. printf("\n");
  2523. return true;
  2524. }
  2525. bool ApplicationManager::OnPreWarning(const char* window, const char* fileName, int line, [[maybe_unused]] const char* func, const char* message)
  2526. {
  2527. printf("\n");
  2528. printf("[WARN] - %s:\n", window);
  2529. if (m_showVerboseOutput)
  2530. {
  2531. printf("(%s - Line %i)\n", fileName, line);
  2532. }
  2533. printf("%s", message);
  2534. printf("\n");
  2535. return true;
  2536. }
  2537. bool ApplicationManager::OnPrintf(const char* window, const char* message)
  2538. {
  2539. if (window == AssetBundler::AppWindowName || (m_showVerboseOutput && window == AssetBundler::AppWindowNameVerbose))
  2540. {
  2541. printf("%s", message);
  2542. return true;
  2543. }
  2544. return !m_showVerboseOutput;
  2545. }
  2546. } // namespace AssetBundler
  2547. #include <source/utils/moc_applicationManager.cpp>