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()));