3
0

applicationManager.cpp 138 KB

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