| 1 | /*++ |
| 2 | |
| 3 | Copyright (c) Microsoft. All rights reserved. |
| 4 | |
| 5 | Module Name: |
| 6 | |
| 7 | BuildImageCallback.h |
| 8 | |
| 9 | Abstract: |
| 10 | |
| 11 | This file contains the BuildImageCallback definition |
| 12 | |
| 13 | --*/ |
| 14 | #pragma once |
| 15 | #include "ContainerModel.h" |
| 16 | #include "Terminal.h" |
| 17 | #include "SessionService.h" |
| 18 | #include "VTSupport.h" |
| 19 | #include <deque> |
| 20 | #include <map> |
| 21 | |
| 22 | namespace wsl::windows::wslc::services { |
| 23 | class DECLSPEC_UUID("3EDD5DBF-CA6C-4CF7-923A-AD94B6A732E5") BuildImageCallback |
| 24 | : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>, IProgressCallback, IFastRundown> |
| 25 | { |
| 26 | public: |
| 27 | // The cancel event handle must remain valid for the lifetime of this callback. |
| 28 | // Mode selects the rendering style (Auto is expected to already be resolved to Tty/Plain by the caller). |
| 29 | BuildImageCallback(Terminal& terminal, HANDLE cancelEvent, bool verbose, models::ProgressMode mode = models::ProgressMode::Tty) : |
| 30 | m_terminal(terminal), m_verbose(verbose), m_cancelEvent(cancelEvent), m_mode(mode), m_color(mode == models::ProgressMode::Tty) |
| 31 | { |
| 32 | } |
| 33 | ~BuildImageCallback(); |
| 34 | HRESULT OnProgress(LPCSTR status, LPCSTR id, ULONGLONG current, ULONGLONG total) override; |
| 35 | |
| 36 | private: |
| 37 | static constexpr int c_maxDisplayLines = 16; |
| 38 | static constexpr auto c_redrawInterval = std::chrono::milliseconds(50); |
| 39 | static constexpr size_t c_maxAllLinesBytes = 10 * 1024 * 1024; // 10 MiB cap on retained log output for error replay. |
| 40 | |
| 41 | void CollapseWindow(); |
| 42 | void Redraw(); |
| 43 | void RedrawIfNeeded(); |
| 44 | bool IsCancelled() const; |
| 45 | // Appends a log chunk to the error-replay buffer, enforcing the retained-bytes cap. |
| 46 | void CaptureForReplay(std::string_view text); |
| 47 | // Returns the sequence when color is enabled for this callback, else an empty (no-op) sequence so |
| 48 | // the Terminal emits nothing for it. Used to strip color from the sequences emitted in Tty mode. |
| 49 | const wsl::windows::common::vt::Sequence& Color(const wsl::windows::common::vt::Sequence& sequence) const; |
| 50 | |
| 51 | Terminal& m_terminal; |
| 52 | const bool m_verbose; |
| 53 | const HANDLE m_cancelEvent; |
| 54 | const models::ProgressMode m_mode; |
| 55 | const bool m_color; |
| 56 | // In-place rendering (cursor moves, erases and redraws) is only used for Tty mode on a VT |
| 57 | // console. Plain mode appends one line at a time so its output carries no cursor control and |
| 58 | // is identical whether it goes to a console or a redirected stream. |
| 59 | bool m_renderInPlace = m_mode == models::ProgressMode::Tty && m_terminal.IsVTEnabled(Terminal::Level::Info); |
| 60 | std::deque<std::string> m_lines; |
| 61 | // Each entry already contains the trailing newline so the bytes match what's replayed. |
| 62 | // TODO: Track logs per step so the destructor can replay only the failing step's |
| 63 | // logs on error, rather than every line captured during the build. |
| 64 | std::deque<std::string> m_allLines; |
| 65 | size_t m_allLinesBytes = 0; |
| 66 | std::string m_pendingLine; |
| 67 | int m_displayedLines = 0; |
| 68 | std::chrono::steady_clock::time_point m_lastRedraw{}; |
| 69 | // Per-entry pull progress lines, keyed by entry id. Updated in place by Redraw. std::map so order is consistent. |
| 70 | std::map<std::string, std::string> m_pullLines; |
| 71 | // Reused across Redraw() calls so the backing allocation grows to the high-water |
| 72 | // mark and is then reused rather than re-allocated every frame. |
| 73 | std::wstring m_frameBuffer; |
| 74 | // Captured at construction so the destructor can detect destruction during exception unwinding. |
| 75 | int m_uncaughtExceptions = std::uncaught_exceptions(); |
| 76 | }; |
| 77 | } // namespace wsl::windows::wslc::services |