Improved details for build and pull#40596
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds richer progress reporting to wslc build and wslc pull: pull now shows progress bars with current/total bytes, and build shows per-layer download progress lines that update in place along with colored build-step output.
Changes:
- Plumb
current/totalbyte counts from BuildKit status throughBuildKitStatusJSON,reportProgress, and into the callbacks. - Render a fixed-width progress bar with
FormatBytesoutput inImageProgressCallback, and truncate to console width to avoid wrap artifacts. - In
BuildImageCallback, maintain a per-entrym_pullLinesmap rendered each redraw, and colorize permanent build-step lines in teal.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/windows/wslcsession/WSLCSession.cpp | Extends reportProgress to forward current/total and emits per-entry progress when entry.total > 0. |
| src/windows/wslc/services/ImageProgressCallback.cpp | Replaces percent text with a 30-char progress bar plus formatted byte counts; truncates to console width. |
| src/windows/wslc/services/BuildImageCallback.h | Adds m_pullLines map and <map> include. |
| src/windows/wslc/services/BuildImageCallback.cpp | Stores per-id pull status, redraws periodically, and wraps permanent lines in teal ANSI escapes. |
| src/windows/inc/docker_schema.h | Adds current/total fields to BuildKitStatus deserialization. |
| src/shared/inc/stringshared.h | New FormatBytes helper producing GB/MB/KB/B strings. |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
| // accepting any non-empty id, so future or unrelated id usage defaults to permanent. | ||
| const bool isLog = (id != nullptr && std::string_view{id} == "log"); | ||
|
|
||
| // Pull/download progress: update the per-entry map so Redraw can show each entry |
There was a problem hiding this comment.
I'm not sure we are handling this correctly when m_isConsole is false. We should probably skip the whole callback stuff when non in an interactive terminal.
There was a problem hiding this comment.
I think this would break AIs who are scraping wslc.exe build output. Right now we output something like this:
PS C:\cDev\copilot\build-test> cat .\dockerfilesimple.log
Building image from directory: .
[1/2] FROM docker.io/library/ubuntu:24.04@sha256:c4a8d5503dfb2a3eb8ab5f807da5bc69a85730fb49b5cfca2330194ebcc41c7b
[2/2] RUN echo 123
exporting to image
| exporting layers
| writing image sha256:780c43a5ab95735b080898e63db96c3feebdd05591a0a934bc3252fe70201004
| naming to docker.io/library/test
PS C:\cDev\copilot\build-test>
I think this is pretty reasonable and gives the right info on all the steps.
…m/microsoft/WSL into user/crloewen/better-build-output
| inline std::wstring FormatBytes(uint64_t bytes) | ||
| { |
There was a problem hiding this comment.
I am wondering if we could move this to wsl::windows::common::string and use the windows StrFormatByteSizeEx. It does have a slightly different oputput. StrFormatByteSizeEx uses 1024-based math with the Windows-conventional labels (KB, MB, GB, TB) — i.e. 1.00 KB means 1024 bytes. The current helper is 1000-based. So switching will change the numbers users see during pulls which would diverge from docker's behavior. However, it does give localized decimal seperator. I could see this going either way.
ALSO, if we are making a helper for this, we should probably get rid of the other FormatBytes method in ContainerTasks.cpp:37 and just use a common helper.
| while (!wide.empty() && (wide.back() == L'\n' || wide.back() == L'\r')) | ||
| { | ||
| terminator.insert(terminator.begin(), wide.back()); | ||
| wide.pop_back(); | ||
| } |
There was a problem hiding this comment.
This is a bit hard to reason about. I think this can be simplified with std::wstring::find_last_not_of(L"\r\n").
const auto bodyLength = wide.find_last_not_of(L"\r\n") + 1; // or textLength or whatever you prefer (I am bad at naming stuff)
const auto newlines = wide.substr(bodyLength);
wide.resize(bodyLength);
WriteTerminal(std::format(L"\033[36m{}\033[0m{}", wide, newlines));
| const bool isLog = (id != nullptr && std::string_view{id} == "log"); | ||
|
|
||
| // Pull/download progress: update the per-entry map so Redraw can show each entry | ||
| // on a single line that updates in place. |
There was a problem hiding this comment.
Nit: The OnProgress body asks the same three questions in two different places — "does the message have an id?", "is it the log sentinel?", "is it per-layer pull progress?" — and the id != nullptr && *id != '\0' check appears several times. The verbose/non-TTY branch and the interactive branch also independently re-derive what kind of message this is.
const std::string_view idView = (id != nullptr) ? id : std::string_view{};
const bool isLog = (idView == "log");
const bool isPullProgress = (!idView.empty() && total > 0 && !isLog);
if (m_verbose || !m_isConsole)
{
if (!isPullProgress)
{
wprintf(L"%hs", status);
}
return S_OK;
}
if (isPullProgress) { return HandlePullProgress(idStr, status); }
if (isLog) { return HandleLogChunk(status); }
return HandleStepHeader(status);
| terminator.insert(terminator.begin(), wide.back()); | ||
| wide.pop_back(); | ||
| } | ||
| wide = std::format(L"\033[36m{}\033[0m{}", wide, terminator); |
There was a problem hiding this comment.
Really nit, don't hate me for this. There are a lot of these ANSI escape sequences scattered throught the file, it would be nice to have to have these defined as constants for readability. Either at the top of this file or a common header. (IDK if its used elsewhere).
For example, this format could read like: wide = std::format(L"{}{}{}{}", ansi::Cyan, wide, ansi::ResetColor, terminator);
Then its a lot easier to understand what is happening.
There was a problem hiding this comment.
Actually, I did a brief search with copilot, and alledgedly its also used in WSLCTests.cpp, WSLCE2EHelpers.h, ImageProgressCallback.cpp, BuildImageCallback.cpp. So this could warrant placing in stringshared.h or deps.h. The test files i mentioned use the VT_* constants.
Summary of the Pull Request
Added some small details to
wslc buildandwslc pull.Specifically this just adds a 'total MB' to build and progress bars and total layer sizes to pull.
Pull
Before:

After:

Build
Before:

After:

PR Checklist
Detailed Description of the Pull Request / Additional comments
Scoped it to be as small as possible.
Validation Steps Performed
Tested behaviour before and after.