ExecutionContext.h (9432B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #pragma once 4 #include "winget/ThreadGlobals.h" 5 #include "ExecutionReporter.h" 6 #include "ExecutionArgs.h" 7 #include "ExecutionContextData.h" 8 #include "CompletionData.h" 9 #include "CheckpointManager.h" 10 #include <AppInstallerProgress.h> 11 #include <winget/Checkpoint.h> 12 13 #include <string_view> 14 15 #define WINGET_CATCH_RESULT_EXCEPTION_STORE(exceptionHR) catch (const wil::ResultException& re) { exceptionHR = re.GetErrorCode(); } 16 #define WINGET_CATCH_HRESULT_EXCEPTION_STORE(exceptionHR) catch (const winrt::hresult_error& hre) { exceptionHR = hre.code(); } 17 #define WINGET_CATCH_COMMAND_EXCEPTION_STORE(exceptionHR) catch (const ::AppInstaller::CLI::CommandException&) { exceptionHR = APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS; } 18 #define WINGET_CATCH_POLICY_EXCEPTION_STORE(exceptionHR) catch (const ::AppInstaller::Settings::GroupPolicyException&) { exceptionHR = APPINSTALLER_CLI_ERROR_BLOCKED_BY_POLICY; } 19 #define WINGET_CATCH_STD_EXCEPTION_STORE(exceptionHR, genericHR) catch (const std::exception&) { exceptionHR = genericHR; } 20 #define WINGET_CATCH_ALL_EXCEPTION_STORE(exceptionHR, genericHR) catch (...) { exceptionHR = genericHR; } 21 #define WINGET_CATCH_STORE(exceptionHR, genericHR) \ 22 WINGET_CATCH_RESULT_EXCEPTION_STORE(exceptionHR) \ 23 WINGET_CATCH_HRESULT_EXCEPTION_STORE(exceptionHR) \ 24 WINGET_CATCH_COMMAND_EXCEPTION_STORE(exceptionHR) \ 25 WINGET_CATCH_POLICY_EXCEPTION_STORE(exceptionHR) \ 26 WINGET_CATCH_STD_EXCEPTION_STORE(exceptionHR, genericHR) \ 27 WINGET_CATCH_ALL_EXCEPTION_STORE(exceptionHR, genericHR) 28 29 // Terminates the Context with some logging to indicate the location. 30 // Also returns from the current function. 31 #define AICLI_TERMINATE_CONTEXT_ARGS(_context_,_hr_,_ret_) \ 32 do { \ 33 _context_.Terminate(_hr_, __FILE__, __LINE__); \ 34 return _ret_; \ 35 } while(0,0) 36 37 // Terminates the Context named 'context' with some logging to indicate the location. 38 // Also returns from the current function. 39 #define AICLI_TERMINATE_CONTEXT(_hr_) AICLI_TERMINATE_CONTEXT_ARGS(context,_hr_,) 40 41 // Terminates the Context named 'context' with some logging to indicate the location. 42 // Also returns the specified value from the current function. 43 #define AICLI_TERMINATE_CONTEXT_RETURN(_hr_,_ret_) AICLI_TERMINATE_CONTEXT_ARGS(context,_hr_,_ret_) 44 45 // Returns if the context is terminated. 46 #define AICLI_RETURN_IF_TERMINATED(_context_) if ((_context_).IsTerminated()) { return; } 47 48 namespace AppInstaller::CLI 49 { 50 struct Command; 51 } 52 53 namespace AppInstaller::CLI::Workflow 54 { 55 struct WorkflowTask; 56 enum class ExecutionStage : uint32_t; 57 } 58 59 namespace AppInstaller::CLI::Execution 60 { 61 // bit masks used as Context flags 62 enum class ContextFlag : int 63 { 64 None = 0x0, 65 InstallerExecutionUseUpdate = 0x1, 66 InstallerHashMatched = 0x2, 67 InstallerTrusted = 0x4, 68 // Allows a failure in a single source to generate a warning rather than an error. 69 // TODO: Remove when the source interface is refactored. 70 TreatSourceFailuresAsWarning = 0x8, 71 ShowSearchResultsOnPartialFailure = 0x10, 72 DisableInteractivity = 0x40, 73 BypassIsStoreClientBlockedPolicyCheck = 0x80, 74 InstallerDownloadOnly = 0x100, 75 Resume = 0x200, 76 RebootRequired = 0x400, 77 RegisterResume = 0x800, 78 InstallerExecutionUseRepair = 0x1000, 79 }; 80 81 DEFINE_ENUM_FLAG_OPERATORS(ContextFlag); 82 83 #ifndef AICLI_DISABLE_TEST_HOOKS 84 HWND GetWindowHandle(); 85 86 bool WaitForAppShutdownEvent(); 87 #endif 88 89 // Callback to log data actions. 90 void ContextEnumBasedVariantMapActionCallback(const void* map, Data data, EnumBasedVariantMapAction action); 91 92 // The context within which all commands execute. 93 // Contains input/output via Execution::Reporter and 94 // arguments via Execution::Args. 95 struct Context : EnumBasedVariantMap<Data, details::DataMapping, ContextEnumBasedVariantMapActionCallback>, ICancellable 96 { 97 Context() = default; 98 Context(std::ostream& out, std::istream& in) : Reporter(out, in) {} 99 100 // Constructor for creating a sub-context. 101 Context(Execution::Reporter& reporter, ThreadLocalStorage::WingetThreadGlobals& threadGlobals) : 102 Reporter(reporter, Execution::Reporter::clone_t{}), 103 m_threadGlobals(threadGlobals, ThreadLocalStorage::WingetThreadGlobals::create_sub_thread_globals_t{}) {} 104 105 virtual ~Context(); 106 107 // The path for console input/output for all functionality. 108 Reporter Reporter; 109 110 // The arguments given to execute with. 111 Args Args; 112 113 // Creates a empty context, inheriting 114 Context CreateEmptyContext(); 115 116 // Creates a child of this context. 117 virtual std::unique_ptr<Context> CreateSubContext(); 118 119 // Enables reception of CTRL signals and window messages. 120 void EnableSignalTerminationHandler(bool enabled = true); 121 122 // Applies changes based on the parsed args. 123 void UpdateForArgs(); 124 125 // Returns a value indicating whether the context is terminated. 126 bool IsTerminated() const { return m_isTerminated; } 127 128 // Resets the context to a nonterminated state. 129 void ResetTermination() { m_terminationHR = S_OK; m_isTerminated = false; } 130 131 // Gets the HRESULT reason for the termination. 132 HRESULT GetTerminationHR() const { return m_terminationHR; } 133 134 // Set the context to the terminated state. 135 void Terminate(HRESULT hr, std::string_view file = {}, size_t line = {}); 136 137 // Set the termination hr of the context. 138 void SetTerminationHR(HRESULT hr); 139 140 // Cancel the context; this terminates it as well as informing any in progress task to stop cooperatively. 141 // Multiple attempts with CancelReason::CancelSignal may cause the process to simply exit. 142 // The bypassUser indicates whether the user should be asked for cancellation (does not currently have any effect). 143 void Cancel(CancelReason reason, bool bypassUser = false) override; 144 145 // Gets context flags 146 ContextFlag GetFlags() const 147 { 148 return m_flags; 149 } 150 151 // Set context flags 152 void SetFlags(ContextFlag flags) 153 { 154 WI_SetAllFlags(m_flags, flags); 155 } 156 157 // Clear context flags 158 void ClearFlags(ContextFlag flags) 159 { 160 WI_ClearAllFlags(m_flags, flags); 161 } 162 163 virtual void SetExecutionStage(Workflow::ExecutionStage stage); 164 165 // Get Globals for Current Context 166 AppInstaller::ThreadLocalStorage::WingetThreadGlobals& GetThreadGlobals(); 167 168 std::unique_ptr<AppInstaller::ThreadLocalStorage::PreviousThreadGlobals> SetForCurrentThread(); 169 170 // Gets the executing command 171 AppInstaller::CLI::Command* GetExecutingCommand() { return m_executingCommand; } 172 173 // Sets the executing command 174 void SetExecutingCommand(AppInstaller::CLI::Command* command) { m_executingCommand = command; } 175 176 #ifndef AICLI_DISABLE_TEST_HOOKS 177 // Enable tests to override behavior 178 bool ShouldExecuteWorkflowTask(const Workflow::WorkflowTask& task); 179 #endif 180 181 // Returns the resume id. 182 std::string GetResumeId(); 183 184 // Called by the resume command. Loads the checkpoint manager with the resume id and returns the automatic checkpoint. 185 std::optional<AppInstaller::Checkpoints::Checkpoint<AppInstaller::Checkpoints::AutomaticCheckpointData>> LoadCheckpoint(const std::string& resumeId); 186 187 // Returns data checkpoints in the order of latest checkpoint to earliest. 188 std::vector<AppInstaller::Checkpoints::Checkpoint<Execution::Data>> GetCheckpoints(); 189 190 // Creates a checkpoint for the provided context data. 191 void Checkpoint(std::string_view checkpointName, std::vector<Execution::Data> contextData); 192 193 protected: 194 // Copies the args that are also needed in a sub-context. E.g., silent 195 void CopyArgsToSubContext(Context* subContext); 196 197 // Copies the execution data that are also needed in a sub-context. E.g., shared installer download authenticator map 198 void CopyDataToSubContext(Context* subContext); 199 200 // Neither virtual functions nor member fields can be inside AICLI_DISABLE_TEST_HOOKS 201 // or we could have ODR violations that lead to nasty bugs. So we will simply never 202 // use this if AICLI_DISABLE_TEST_HOOKS is defined. 203 std::function<bool(const Workflow::WorkflowTask&)> m_shouldExecuteWorkflowTask; 204 205 private: 206 DestructionToken m_disableSignalTerminationHandlerOnExit = false; 207 bool m_isTerminated = false; 208 HRESULT m_terminationHR = S_OK; 209 size_t m_CtrlSignalCount = 0; 210 ContextFlag m_flags = ContextFlag::None; 211 Workflow::ExecutionStage m_executionStage = Workflow::ExecutionStage::Initial; 212 AppInstaller::ThreadLocalStorage::WingetThreadGlobals m_threadGlobals; 213 AppInstaller::CLI::Command* m_executingCommand = nullptr; 214 std::unique_ptr<AppInstaller::Checkpoints::CheckpointManager> m_checkpointManager; 215 }; 216 }