applicationManager.cpp 139 KB

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