@samitouri / QOSAMI-WSL / commits / 80d300ab

wslc: add --size to inspect for docker parity (#41489)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

ggarzia-MSFT committed Sep 8, 2026 at 09:21 UTC 80d300ab0a51edc4032fcc9919fca7784ac8fc8f
20 files changed +169 -28
localization/strings/en-US/Resources.resw
+7
@@ -3352,6 +3352,13 @@ On first run, creates the file with all settings commented out at their defaults
3352 <data name="WSLCCLI_SourceArgDescription" xml:space="preserve">
3353 <value>Current or existing image reference in the image-name[:tag] format</value>
3354 </data>
3355 + <data name="WSLCCLI_InspectSizeArgDescription" xml:space="preserve">
3356 + <value>Display total file sizes if the type is container</value>
3357 + </data>
3358 + <data name="WSLCCLI_InspectSizeIgnoredWarning" xml:space="preserve">
3359 + <value>WARNING: --size ignored for {}</value>
3360 + <comment>{FixedPlaceholder="{}"}{Locked="--size "}Command line arguments, file names and string inserts should not be translated</comment>
3361 + </data>
3362 <data name="WSLCCLI_TagArgDescription" xml:space="preserve">
3363 <value>Tag for the built image</value>
3364 </data>
src/windows/common/WSLCContainerLauncher.cpp
+1 -1
@@ -527,7 +527,7 @@ RunningWSLCContainer WSLCContainerLauncher::Launch(IWSLCSession& Session, WSLCCo
527 wsl::windows::common::wslc_schema::InspectContainer RunningWSLCContainer::Inspect()
528 {
529 wil::unique_cotaskmem_ansistring output;
530 - THROW_IF_FAILED(m_container->Inspect(&output));
530 + THROW_IF_FAILED(m_container->Inspect(FALSE, &output));
531
532 return wsl::shared::FromJson<wslc_schema::InspectContainer>(output.get());
533 }
src/windows/inc/docker_schema.h
+4 -1
@@ -543,8 +543,11 @@ struct InspectContainer
543 HostConfig HostConfig;
544 std::vector<InspectMount> Mounts;
545 NetworkSettings NetworkSettings;
546 + std::optional<int64_t> SizeRw;
547 + std::optional<int64_t> SizeRootFs;
548
547 - NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(InspectContainer, Id, Name, Created, Image, State, Config, HostConfig, Mounts, NetworkSettings);
549 + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
550 + InspectContainer, Id, Name, Created, Image, State, Config, HostConfig, Mounts, NetworkSettings, SizeRw, SizeRootFs);
551 };
552
553 struct InspectExec
src/windows/inc/wslc_schema.h
+23 -1
@@ -157,10 +157,32 @@ struct InspectContainer
157 std::vector<InspectMount> Mounts;
158 std::map<std::string, std::string> Labels;
159 InspectNetworkSettings NetworkSettings;
160 + std::optional<std::int64_t> SizeRw;
161 + std::optional<std::int64_t> SizeRootFs;
162
161 - NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(InspectContainer, Id, Name, Created, Image, State, HostConfig, Config, Ports, Mounts, Labels, NetworkSettings);
163 + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
164 + InspectContainer, Id, Name, Created, Image, State, HostConfig, Config, Ports, Mounts, Labels, NetworkSettings, SizeRw, SizeRootFs);
165 };
166
167 +// Serializes a container inspect document. SizeRw and SizeRootFs are only populated when the
168 +// daemon was asked to compute them, so the keys are omitted entirely when they have no value.
169 +inline nlohmann::json ToInspectJson(const InspectContainer& container)
170 +{
171 + nlohmann::json document = container;
172 +
173 + if (!container.SizeRw.has_value())
174 + {
175 + document.erase("SizeRw");
176 + }
177 +
178 + if (!container.SizeRootFs.has_value())
179 + {
180 + document.erase("SizeRootFs");
181 + }
182 +
183 + return document;
184 +}
185 +
186 struct ImageConfig
187 {
188 std::optional<std::vector<std::string>> Cmd;
src/windows/service/inc/wslc.idl
+1 -1
@@ -571,7 +571,7 @@ interface IWSLCContainer : IUnknown
571 HRESULT GetState([out] WSLCContainerState* State);
572 HRESULT GetInitProcess([out] IWSLCProcess** Process);
573 HRESULT Exec([in, ref] const WSLCProcessOptions* Options, [in, unique] const WSLCProcessStartOptions* StartOptions, [out] IWSLCProcess** Process);
574 - HRESULT Inspect([out] LPSTR* Output);
574 + HRESULT Inspect([in] BOOL Size, [out] LPSTR* Output);
575 HRESULT Logs([in] WSLCLogsFlags Flags, [out] WSLCHandle* Stdout, [out] WSLCHandle* Stderr, [in] LONGLONG Since, [in] LONGLONG Until, [in] ULONGLONG Tail);
576 HRESULT GetId([out, string] WSLCContainerId Id);
577 HRESULT GetName([out, string] LPSTR* Name);
src/windows/wslc/arguments/ArgumentDefinitions.h
+1
@@ -122,6 +122,7 @@ _(Session, "session", NO_ALIAS, Kind::Value,
122 _(ShmSize, "shm-size", NO_ALIAS, Kind::Value, int64_t, Localization::WSLCCLI_ShmSizeArgDescription()) \
123 _(StoragePath, "storage-path", NO_ALIAS, Kind::Positional, NoConversion, Localization::WSLCCLI_StoragePathArgDescription()) \
124 _(Signal, "signal", L"s", Kind::Value, WSLCSignal, Localization::WSLCCLI_SignalArgDescription()) \
125 +_(Size, "size", L"s", Kind::Flag, NoConversion, Localization::WSLCCLI_InspectSizeArgDescription()) \
126 _(Source, "source", NO_ALIAS, Kind::Positional, NoConversion, Localization::WSLCCLI_SourceArgDescription()) \
127 _(StopSignal, "stop-signal", NO_ALIAS, Kind::Value, WSLCSignal, Localization::WSLCCLI_StopSignalArgDescription()) \
128 _(StopTimeout, "stop-timeout", NO_ALIAS, Kind::Value, int, Localization::WSLCCLI_StopTimeoutArgDescription()) \
src/windows/wslc/commands/ContainerInspectCommand.cpp
+1
@@ -28,6 +28,7 @@ std::vector<Argument> ContainerInspectCommand::GetArguments() const
28 {
29 return {
30 Argument::Create(ArgType::ContainerId, {.Required = true, .Limit = Limit::Unlimited}),
31 + Argument::Create(ArgType::Size),
32 Argument::Create(ArgType::InspectFormat),
33 };
34 }
src/windows/wslc/commands/InspectCommand.cpp
+1
@@ -24,6 +24,7 @@ std::vector<Argument> InspectCommand::GetArguments() const
24 return {
25 Argument::Create(ArgType::ObjectId, {.Required = true, .Limit = Limit::Unlimited}),
26 Argument::Create(ArgType::Type),
27 + Argument::Create(ArgType::Size),
28 Argument::Create(ArgType::InspectFormat),
29 };
30 }
src/windows/wslc/services/ContainerService.cpp
+2 -2
@@ -776,13 +776,13 @@ int ContainerService::Exec(Terminal& terminal, Session& session, const std::stri
776 return ConsoleService::AttachToCurrentConsole(terminal, console, processLauncher.Launch(*container));
777 }
778
779 -InspectContainer ContainerService::Inspect(Session& session, const std::string& id)
779 +InspectContainer ContainerService::Inspect(Session& session, const std::string& id, bool size)
780 {
781 [[maybe_unused]] auto operation = session.BeginContainerOperation();
782 wil::com_ptr<IWSLCContainer> container;
783 THROW_IF_FAILED(session.Get()->OpenContainer(id.c_str(), &container));
784 wil::unique_cotaskmem_ansistring output;
785 - THROW_IF_FAILED(container->Inspect(&output));
785 + THROW_IF_FAILED(container->Inspect(size ? TRUE : FALSE, &output));
786 return wsl::shared::FromJson<InspectContainer>(output.get());
787 }
788
src/windows/wslc/services/ContainerService.h
+1 -1
@@ -64,7 +64,7 @@ struct ContainerService
64 static void Export(models::Session& session, const std::string& id, HANDLE outputHandle);
65 static void CopyToContainer(models::Session& session, const std::string& id, const std::string& destPath, HANDLE inputHandle, ULONGLONG contentSize);
66 static void CopyFromContainer(models::Session& session, const std::string& id, const std::string& srcPath, HANDLE outputHandle);
67 - static wsl::windows::common::wslc_schema::InspectContainer Inspect(models::Session& session, const std::string& id);
67 + static wsl::windows::common::wslc_schema::InspectContainer Inspect(models::Session& session, const std::string& id, bool size = false);
68 static void Logs(models::Session& session, const std::string& id, bool follow, bool timestamps, LONGLONG since, LONGLONG until, ULONGLONG tail = 0);
69 static wsl::windows::common::docker_schema::ContainerStats Stats(models::Session& session, const std::string& id);
70 static models::PruneContainersResult Prune(models::Session& session);
src/windows/wslc/tasks/ContainerTasks.cpp
+12 -4
@@ -161,11 +161,12 @@ ContainerOutputInformation ToContainerOutput(const ContainerInformation& contain
161
162 namespace wsl::windows::wslc::task {
163
164 -static bool TryInspectContainer(Terminal& terminal, Session& session, const std::string& containerId, std::optional<wslc_schema::InspectContainer>& inspectData)
164 +static bool TryInspectContainer(
165 + Terminal& terminal, Session& session, const std::string& containerId, std::optional<wslc_schema::InspectContainer>& inspectData, bool size = false)
166 {
167 try
168 {
168 - inspectData = ContainerService::Inspect(session, containerId);
169 + inspectData = ContainerService::Inspect(session, containerId, size);
170 return true;
171 }
172 catch (const wil::ResultException& ex)
@@ -239,10 +240,11 @@ void InspectContainers(CLIExecutionContext& context)
240 auto& session = context.Data.Get<Data::Session>();
241 auto containerIds = context.Args.GetAllValues<ArgType::ContainerId>();
242 std::vector<wsl::windows::common::wslc_schema::InspectContainer> result;
243 + const bool size = context.Args.GetValue<ArgType::Size>();
244 for (const auto& id : containerIds)
245 {
246 std::optional<wslc_schema::InspectContainer> inspectData;
245 - if (TryInspectContainer(context.Terminal, session, WideToMultiByte(id), inspectData))
247 + if (TryInspectContainer(context.Terminal, session, WideToMultiByte(id), inspectData, size))
248 {
249 result.push_back(*inspectData);
250 }
@@ -252,7 +254,13 @@ void InspectContainers(CLIExecutionContext& context)
254 }
255 }
256
255 - auto json = ToJson(result, context.Args.GetValue<ArgType::InspectFormat>(c_jsonPrettyPrintIndent));
257 + nlohmann::json array = nlohmann::json::array();
258 + for (const auto& entry : result)
259 + {
260 + array.push_back(wslc_schema::ToInspectJson(entry));
261 + }
262 +
263 + auto json = array.dump(context.Args.GetValue<ArgType::InspectFormat>(c_jsonPrettyPrintIndent));
264 context.Terminal.Output(L"{}\n", MultiByteToWide(json));
265 }
266
src/windows/wslc/tasks/InspectTasks.cpp
+18 -4
@@ -53,9 +53,10 @@ static bool TryInspectImage(wsl::windows::wslc::models::Session& session, const
53 return TryInspect([&]() { result = services::ImageService::Inspect(session, image); }, WSLC_E_IMAGE_NOT_FOUND);
54 }
55
56 -static bool TryInspectContainer(wsl::windows::wslc::models::Session& session, const std::string& containerId, std::optional<wslc_schema::InspectContainer>& result)
56 +static bool TryInspectContainer(
57 + wsl::windows::wslc::models::Session& session, const std::string& containerId, std::optional<wslc_schema::InspectContainer>& result, bool size)
58 {
58 - return TryInspect([&]() { result = services::ContainerService::Inspect(session, containerId); }, WSLC_E_CONTAINER_NOT_FOUND);
59 + return TryInspect([&]() { result = services::ContainerService::Inspect(session, containerId, size); }, WSLC_E_CONTAINER_NOT_FOUND);
60 }
61
62 static bool TryInspectNetwork(wsl::windows::wslc::models::Session& session, const std::string& networkName, std::optional<wslc_schema::Network>& result)
@@ -81,6 +82,16 @@ void Inspect(CLIExecutionContext& context)
82 type = context.Args.GetValue<ArgType::Type>();
83 }
84
85 + const bool size = context.Args.GetValue<ArgType::Size>();
86 +
87 + // Only containers carry file size information; every other type warns and continues.
88 + const auto warnSizeIgnored = [&](const wchar_t* objectType) {
89 + if (size)
90 + {
91 + context.Terminal.Error(L"{}\n", Localization::WSLCCLI_InspectSizeIgnoredWarning(objectType));
92 + }
93 + };
94 +
95 for (const auto& objectId : objectIds)
96 {
97 auto id = WideToMultiByte(objectId);
@@ -89,20 +100,23 @@ void Inspect(CLIExecutionContext& context)
100 std::optional<wslc_schema::Network> network;
101 std::optional<wslc_schema::InspectVolume> volume;
102
92 - if (WI_IsFlagSet(type, InspectType::Container) && TryInspectContainer(session, id, container))
103 + if (WI_IsFlagSet(type, InspectType::Container) && TryInspectContainer(session, id, container, size))
104 {
94 - array.push_back(std::move(*container));
105 + array.push_back(wslc_schema::ToInspectJson(*container));
106 }
107 else if (WI_IsFlagSet(type, InspectType::Image) && TryInspectImage(session, id, image))
108 {
109 + warnSizeIgnored(L"image");
110 array.push_back(std::move(*image));
111 }
112 else if (WI_IsFlagSet(type, InspectType::Network) && TryInspectNetwork(session, id, network))
113 {
114 + warnSizeIgnored(L"network");
115 array.push_back(std::move(*network));
116 }
117 else if (WI_IsFlagSet(type, InspectType::Volume) && TryInspectVolume(session, id, volume))
118 {
119 + warnSizeIgnored(L"volume");
120 array.push_back(std::move(*volume));
121 }
122 else
src/windows/wslcsession/DockerHTTPClient.cpp
+5 -2
@@ -355,9 +355,12 @@ void DockerHTTPClient::DeleteContainer(const std::string& Id, bool Force, bool D
355 Transaction(verb::delete_, url);
356 }
357
358 -docker_schema::InspectContainer DockerHTTPClient::InspectContainer(const std::string& Id)
358 +docker_schema::InspectContainer DockerHTTPClient::InspectContainer(const std::string& Id, bool Size)
359 {
360 - return Transaction<EmptyRequest, docker_schema::InspectContainer>(verb::get, URL::Create("/containers/{}/json", Id));
360 + auto url = URL::Create("/containers/{}/json", Id);
361 + url.SetParameter("size", Size);
362 +
363 + return Transaction<EmptyRequest, docker_schema::InspectContainer>(verb::get, url);
364 }
365
366 docker_schema::ContainerStats DockerHTTPClient::ContainerStats(const std::string& Id)
src/windows/wslcsession/DockerHTTPClient.h
+1 -1
@@ -136,7 +136,7 @@ public:
136 void StopContainer(const std::string& Id, std::optional<WSLCSignal> Signal, std::optional<LONG> TimeoutSeconds);
137 void DeleteContainer(const std::string& Id, bool Force, bool DeleteVolumes = false);
138 void SignalContainer(const std::string& Id, std::optional<WSLCSignal> Signal);
139 - common::docker_schema::InspectContainer InspectContainer(const std::string& Id);
139 + common::docker_schema::InspectContainer InspectContainer(const std::string& Id, bool Size = false);
140 common::docker_schema::ContainerStats ContainerStats(const std::string& Id);
141 common::docker_schema::InspectExec InspectExec(const std::string& Id);
142 wil::unique_socket AttachContainer(const std::string& Id, const std::optional<std::string>& DetachKeys);
src/windows/wslcsession/WSLCContainer.cpp
+15 -6
@@ -2047,6 +2047,8 @@ WslcInspectContainer WSLCContainerImpl::BuildInspectContainer(const DockerInspec
2047 wslcInspect.Name = dockerInspect.Name;
2048 wslcInspect.Created = dockerInspect.Created;
2049 wslcInspect.Image = dockerInspect.Image;
2050 + wslcInspect.SizeRw = dockerInspect.SizeRw;
2051 + wslcInspect.SizeRootFs = dockerInspect.SizeRootFs;
2052
2053 // Map container state.
2054 wslcInspect.State.Status = dockerInspect.State.Status;
@@ -2841,21 +2843,21 @@ const std::string& WSLCContainerImpl::ID() const noexcept
2843 return m_id;
2844 }
2845
2844 -void WSLCContainerImpl::Inspect(LPSTR* Output) const
2846 +void WSLCContainerImpl::Inspect(BOOL Size, LPSTR* Output) const
2847 {
2848 auto lock = m_lock.lock_shared();
2849
2850 try
2851 {
2850 - *Output = wil::make_unique_ansistring<wil::unique_cotaskmem_ansistring>(InspectLockHeld().c_str()).release();
2852 + *Output = wil::make_unique_ansistring<wil::unique_cotaskmem_ansistring>(InspectLockHeld(!!Size).c_str()).release();
2853 }
2854 CATCH_AND_THROW_DOCKER_USER_ERROR("Failed to inspect container '%hs'", m_id.c_str());
2855 }
2856
2855 -std::string WSLCContainerImpl::InspectLockHeld() const
2857 +std::string WSLCContainerImpl::InspectLockHeld(bool Size) const
2858 {
2859 // Get Docker inspect data
2858 - auto dockerInspect = m_runtime.Docker().InspectContainer(m_id);
2860 + auto dockerInspect = m_runtime.Docker().InspectContainer(m_id, Size);
2861
2862 // Convert to WSLC schema
2863 auto wslcInspect = BuildInspectContainer(dockerInspect);
@@ -3290,7 +3292,7 @@ try
3292 }
3293 CATCH_RETURN();
3294
3293 -HRESULT WSLCContainer::Inspect(LPSTR* Output)
3295 +HRESULT WSLCContainer::Inspect(BOOL Size, LPSTR* Output)
3296 try
3297 {
3298 WSLCExecutionContext context(&m_session);
@@ -3300,7 +3302,7 @@ try
3302 *Output = nullptr;
3303
3304 auto vmLease = m_session.Runtime().AcquireVmLease();
3303 - return CallImpl(&WSLCContainerImpl::Inspect, Output);
3305 + return CallImpl(&WSLCContainerImpl::Inspect, Size, Output);
3306 }
3307 CATCH_RETURN();
3308
@@ -3634,3 +3636,10 @@ try
3636 return process.CopyTo(Process);
3637 }
3638 CATCH_RETURN();
3639 +
3640 +HRESULT WSLCContainer::Inspect(LPSTR* Output)
3641 +try
3642 +{
3643 + return Inspect(FALSE, Output);
3644 +}
3645 +CATCH_RETURN();
src/windows/wslcsession/WSLCContainer.h
+4 -3
@@ -109,7 +109,7 @@ public:
109 void GetState(_Out_ WSLCContainerState* State);
110 void GetInitProcess(_Out_ IWSLCProcess** process) const;
111 void Exec(_In_ const WSLCProcessOptions* Options, const WSLCProcessStartOptions* StartOptions, _Out_ IWSLCProcess** Process);
112 - void Inspect(LPSTR* Output) const;
112 + void Inspect(BOOL Size, LPSTR* Output) const;
113 void Logs(WSLCLogsFlags Flags, WSLCHandle* Stdout, WSLCHandle* Stderr, LONGLONG Since, LONGLONG Until, ULONGLONG Tail) const;
114 void Stats(LPSTR* Output) const;
115 void GetLabels(WSLCLabelInformation** Labels, ULONG* Count) const;
@@ -241,7 +241,7 @@ private:
241 // keeping the session's VM alive across idle teardown.
242 __requires_lock_held(m_lock) void UpdateActivityHoldLockHeld() noexcept;
243
244 - __requires_shared_lock_held(m_lock) std::string InspectLockHeld() const;
244 + __requires_shared_lock_held(m_lock) std::string InspectLockHeld(bool Size = false) const;
245
246 // Lifecycle requests hold this shared until their transitions are published; event delivery holds it exclusively.
247 // N.B. Stop releases it across the docker request, which can block indefinitely, and re-checks m_stateGeneration instead.
@@ -320,7 +320,7 @@ public:
320 IFACEMETHOD(GetInitProcess)(_Out_ IWSLCProcess** process) override;
321 IFACEMETHOD(Exec)(_In_ const WSLCProcessOptions* Options, _In_opt_ const WSLCProcessStartOptions* StartOptions, _Out_ IWSLCProcess** Process) override;
322 IFACEMETHOD(Start)(WSLCContainerStartFlags Flags, _In_opt_ const WSLCProcessStartOptions* StartOptions, _In_opt_ IWarningCallback* WarningCallback) override;
323 - IFACEMETHOD(Inspect)(_Out_ LPSTR* Output) override;
323 + IFACEMETHOD(Inspect)(_In_ BOOL Size, _Out_ LPSTR* Output) override;
324 IFACEMETHOD(Logs)(_In_ WSLCLogsFlags Flags, _Out_ WSLCHandle* Stdout, _Out_ WSLCHandle* Stderr, _In_ LONGLONG Since, _In_ LONGLONG Until, _In_ ULONGLONG Tail) override;
325 IFACEMETHOD(GetId)(_Out_ WSLCContainerId Id) override;
326 IFACEMETHOD(GetName)(_Out_ LPSTR* Name) override;
@@ -333,6 +333,7 @@ public:
333 IFACEMETHOD(Start)(_In_ WSLCContainerStartFlags Flags) override;
334 IFACEMETHOD(GetInitProcess)(_Out_ IWSLCCompatProcess** Process) override;
335 IFACEMETHOD(Exec)(_In_ const WSLCCompatProcessOptions* Options, _Out_ IWSLCCompatProcess** Process) override;
336 + IFACEMETHOD(Inspect)(_Out_ LPSTR* Output) override;
337
338 IFACEMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);
339
test/windows/WSLCTests.cpp
+1 -1
@@ -9706,7 +9706,7 @@ class WSLCTests
9706 auto container = launcher.Launch(*m_defaultSession);
9707
9708 // Validate that inspect fails with a null pointer.
9709 - VERIFY_ARE_EQUAL(HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), container.Get().Inspect(nullptr));
9709 + VERIFY_ARE_EQUAL(HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), container.Get().Inspect(FALSE, nullptr));
9710
9711 auto details = container.Inspect();
9712
test/windows/wslc/CommandLineTestCases.h
+10
@@ -211,6 +211,16 @@ COMMAND_LINE_TEST_CASE(L"inspect --format badformat cont1", L"inspect", false)
211 COMMAND_LINE_TEST_CASE(L"container inspect --format json cont1", L"inspect", true)
212 COMMAND_LINE_TEST_CASE(L"container inspect --format table cont1", L"inspect", false)
213 COMMAND_LINE_TEST_CASE(L"container inspect --format badformat cont1", L"inspect", false)
214 +COMMAND_LINE_TEST_CASE(L"inspect --size cont1", L"inspect", true)
215 +COMMAND_LINE_TEST_CASE(L"inspect -s cont1", L"inspect", true)
216 +COMMAND_LINE_TEST_CASE(L"container inspect --size cont1", L"inspect", true)
217 +COMMAND_LINE_TEST_CASE(L"container inspect -s cont1", L"inspect", true)
218 +COMMAND_LINE_TEST_CASE(L"inspect --size --type container cont1", L"inspect", true)
219 +COMMAND_LINE_TEST_CASE(L"inspect --size --type image img1", L"inspect", true)
220 +COMMAND_LINE_TEST_CASE(L"inspect --size", L"inspect", false)
221 +COMMAND_LINE_TEST_CASE(L"image inspect --size img1", L"inspect", false)
222 +COMMAND_LINE_TEST_CASE(L"network inspect --size net1", L"inspect", false)
223 +COMMAND_LINE_TEST_CASE(L"volume inspect --size vol1", L"inspect", false)
224 // The inspect family aliases -f to --format, matching `docker inspect -f`. The alias accepts the
225 // same values as the long name and rejects the same ones.
226 COMMAND_LINE_TEST_CASE(L"inspect -f json cont1", L"inspect", true)
test/windows/wslc/e2e/WSLCE2EContainerInspectTests.cpp
+45
@@ -79,6 +79,51 @@ class WSLCE2EContainerInspectTests
79 VERIFY_ARE_EQUAL("/" + WideToMultiByte(TestContainerName1), inspectData[0].Name);
80 }
81
82 + WSLC_TEST_METHOD(WSLCE2E_Container_Inspect_SizeOption)
83 + {
84 + auto createResult = RunWslc(std::format(L"container create --name {} {}", TestContainerName1, DebianImage.NameAndTag()));
85 + createResult.Verify({.Stderr = L"", .ExitCode = 0});
86 +
87 + // Without --size the document must not carry the size fields.
88 + auto plain = RunWslc(std::format(L"container inspect {}", TestContainerName1));
89 + plain.Verify({.Stderr = L"", .ExitCode = 0});
90 + auto plainDocument = nlohmann::json::parse(WideToMultiByte(plain.Stdout.value()));
91 + VERIFY_ARE_EQUAL(1u, plainDocument.size());
92 + VERIFY_IS_FALSE(plainDocument[0].contains("SizeRw"));
93 + VERIFY_IS_FALSE(plainDocument[0].contains("SizeRootFs"));
94 +
95 + const auto verifySized = [&](const std::wstring& command) {
96 + auto result = RunWslc(command);
97 + result.Verify({.Stderr = L"", .ExitCode = 0});
98 +
99 + auto document = nlohmann::json::parse(WideToMultiByte(result.Stdout.value()));
100 + VERIFY_ARE_EQUAL(1u, document.size());
101 + VERIFY_IS_TRUE(document[0].contains("SizeRw"));
102 + VERIFY_IS_TRUE(document[0].contains("SizeRootFs"));
103 + VERIFY_IS_TRUE(document[0]["SizeRw"].is_number());
104 + VERIFY_IS_TRUE(document[0]["SizeRootFs"].is_number());
105 +
106 + // The image layers always account for more than nothing.
107 + VERIFY_IS_GREATER_THAN(document[0]["SizeRootFs"].get<int64_t>(), static_cast<int64_t>(0));
108 + };
109 +
110 + verifySized(std::format(L"container inspect --size {}", TestContainerName1));
111 + verifySized(std::format(L"inspect --size {}", TestContainerName1));
112 + verifySized(std::format(L"inspect --size --type container {}", TestContainerName1));
113 + }
114 +
115 + WSLC_TEST_METHOD(WSLCE2E_Container_Inspect_SizeOption_ListedInHelp)
116 + {
117 + auto result = RunWslc(L"container inspect --help");
118 + result.Verify({.Stderr = L"", .ExitCode = 0});
119 + VERIFY_IS_TRUE(result.StdoutContainsSubstring(L"--size"));
120 + VERIFY_IS_TRUE(result.StdoutContainsSubstring(L"Display total file sizes if the type is container"));
121 +
122 + result = RunWslc(L"inspect --help");
123 + result.Verify({.Stderr = L"", .ExitCode = 0});
124 + VERIFY_IS_TRUE(result.StdoutContainsSubstring(L"--size"));
125 + }
126 +
127 WSLC_TEST_METHOD(WSLCE2E_Container_Inspect_FormatJson_IsSingleLine)
128 {
129 auto createResult = RunWslc(std::format(L"container create --name {} {}", TestContainerName1, DebianImage.NameAndTag()));
test/windows/wslc/e2e/WSLCE2EInspectTests.cpp
+16
@@ -70,6 +70,22 @@ class WSLCE2EInspectTests
70 result.Verify({.Stdout = L"[]\r\n", .Stderr = std::format(L"Object not found: {}\r\n", InvalidImage.NameAndTag()), .ExitCode = 1});
71 }
72
73 + WSLC_TEST_METHOD(WSLCE2E_Inspect_SizeIgnoredForNonContainerTypes)
74 + {
75 + // --size on an object with no file sizes warns and inspects the object anyway.
76 + auto result = RunWslc(std::format(L"inspect --size {}", DebianImage.NameAndTag()));
77 + result.Verify({.ExitCode = 0});
78 + VERIFY_IS_TRUE(result.StderrContainsSubstring(L"WARNING: --size ignored for image"));
79 +
80 + auto document = nlohmann::json::parse(wsl::shared::string::WideToMultiByte(result.Stdout.value()));
81 + VERIFY_ARE_EQUAL(1u, document.size());
82 + VERIFY_IS_FALSE(document[0].contains("SizeRw"));
83 +
84 + // A plain inspect of the same image emits no warning.
85 + auto plain = RunWslc(std::format(L"inspect {}", DebianImage.NameAndTag()));
86 + plain.Verify({.Stderr = L"", .ExitCode = 0});
87 + }
88 +
89 WSLC_TEST_METHOD(WSLCE2E_Inspect_Image_Success)
90 {
91 auto result = RunWslc(std::format(L"inspect {}", DebianImage.NameAndTag()));