[CLI] Initial support for volume prune (#40737)
* Init volume prune * Clang format * Fix test * Update tests * Update unit
AmirMS committed
Jun 12, 2026 at 23:50 UTC
3973c8632cf97a75192e2631e1b6c418b17615e6
13 files changed
+444
-4
localization/strings/en-US/Resources.resw
+18
@@ -3100,6 +3100,24 @@ On first run, creates the file with all settings commented out at their defaults
3100
<data name="WSLCCLI_VolumeListLongDesc" xml:space="preserve">
3101
<value>Lists all volumes in the session.</value>
3102
</data>
3103
+ <data name="WSLCCLI_VolumePruneDesc" xml:space="preserve">
3104
+ <value>Remove unused local volumes.</value>
3105
+ </data>
3106
+ <data name="WSLCCLI_VolumePruneLongDesc" xml:space="preserve">
3107
+ <value>Removes all unused anonymous local volumes. If --all is specified, also removes unused named volumes. A volume is considered unused when it is not referenced by any container.</value>
3108
+ <comment>{Locked="--all "}Command line arguments, file names and string inserts should not be translated</comment>
3109
+ </data>
3110
+ <data name="WSLCCLI_VolumePruneAllArgDescription" xml:space="preserve">
3111
+ <value>Remove all unused volumes, not just anonymous ones.</value>
3112
+ </data>
3113
+ <data name="WSLCCLI_VolumePruneDeleted" xml:space="preserve">
3114
+ <value>Deleted: {}</value>
3115
+ <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
3116
+ </data>
3117
+ <data name="WSLCCLI_VolumePruneSpaceReclaimed" xml:space="preserve">
3118
+ <value>Total reclaimed space: {}</value>
3119
+ <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
3120
+ </data>
3121
<data name="WSLCCLI_VolumeNameArgDescription" xml:space="preserve">
3122
<value>Volume name</value>
3123
</data>
src/windows/wslc/arguments/ArgumentValidation.cpp
+12
-4
@@ -182,10 +182,7 @@ void ValidateFilter(const std::vector<std::wstring>& values)
182
{
183
for (const auto& value : values)
184
{
185
- if (value.find(L'=') == std::wstring::npos)
186
- {
187
- throw ArgumentException(Localization::WSLCCLI_InvalidFilterError(value));
188
- }
185
+ std::ignore = ParseFilter(value);
186
}
187
}
188
@@ -422,4 +419,15 @@ std::pair<std::string, std::string> ParseDriverOption(const std::wstring& value)
419
return {WideToMultiByte(value.substr(0, pos)), WideToMultiByte(value.substr(pos + 1))};
420
}
421
422
+std::pair<std::string, std::string> ParseFilter(const std::wstring& value)
423
+{
424
+ auto pos = value.find(L'=');
425
+ if (pos == std::wstring::npos)
426
+ {
427
+ throw ArgumentException(Localization::WSLCCLI_InvalidFilterError(value));
428
+ }
429
+
430
+ return {WideToMultiByte(value.substr(0, pos)), WideToMultiByte(value.substr(pos + 1))};
431
+}
432
+
433
} // namespace wsl::windows::wslc::validation
src/windows/wslc/arguments/ArgumentValidation.h
+1
@@ -83,5 +83,6 @@ void ValidateFilter(const std::vector<std::wstring>& values);
83
84
std::pair<std::string, std::string> ParseLabel(const std::wstring& value);
85
std::pair<std::string, std::string> ParseDriverOption(const std::wstring& value);
86
+std::pair<std::string, std::string> ParseFilter(const std::wstring& value);
87
88
} // namespace wsl::windows::wslc::validation
src/windows/wslc/commands/VolumeCommand.cpp
+1
@@ -26,6 +26,7 @@ std::vector<std::unique_ptr<Command>> VolumeCommand::GetCommands() const
26
commands.push_back(std::make_unique<VolumeRemoveCommand>(FullName()));
27
commands.push_back(std::make_unique<VolumeInspectCommand>(FullName()));
28
commands.push_back(std::make_unique<VolumeListCommand>(FullName()));
29
+ commands.push_back(std::make_unique<VolumePruneCommand>(FullName()));
30
return commands;
31
}
32
src/windows/wslc/commands/VolumeCommand.h
+15
@@ -92,4 +92,19 @@ protected:
92
void ValidateArgumentsInternal(const ArgMap& execArgs) const override;
93
void ExecuteInternal(CLIExecutionContext& context) const override;
94
};
95
+
96
+// Prune Command
97
+struct VolumePruneCommand final : public Command
98
+{
99
+ constexpr static std::wstring_view CommandName = L"prune";
100
+ VolumePruneCommand(const std::wstring& parent) : Command(CommandName, parent)
101
+ {
102
+ }
103
+ std::vector<Argument> GetArguments() const override;
104
+ std::wstring ShortDescription() const override;
105
+ std::wstring LongDescription() const override;
106
+
107
+protected:
108
+ void ExecuteInternal(CLIExecutionContext& context) const override;
109
+};
110
} // namespace wsl::windows::wslc
src/windows/wslc/commands/VolumePruneCommand.cpp
new
+52
@@ -0,0 +1,52 @@
1
+/*++
2
+
3
+Copyright (c) Microsoft. All rights reserved.
4
+
5
+Module Name:
6
+
7
+ VolumePruneCommand.cpp
8
+
9
+Abstract:
10
+
11
+ Implementation of command execution logic.
12
+
13
+--*/
14
+
15
+#include "VolumeCommand.h"
16
+#include "CLIExecutionContext.h"
17
+#include "SessionTasks.h"
18
+#include "VolumeTasks.h"
19
+#include "Task.h"
20
+
21
+using namespace wsl::windows::wslc::execution;
22
+using namespace wsl::windows::wslc::task;
23
+using namespace wsl::shared;
24
+
25
+namespace wsl::windows::wslc {
26
+// Volume Prune Command
27
+std::vector<Argument> VolumePruneCommand::GetArguments() const
28
+{
29
+ return {
30
+ Argument::Create(ArgType::All, std::nullopt, std::nullopt, Localization::WSLCCLI_VolumePruneAllArgDescription()),
31
+ Argument::Create(ArgType::Filter, false, NO_LIMIT),
32
+ Argument::Create(ArgType::Session),
33
+ };
34
+}
35
+
36
+std::wstring VolumePruneCommand::ShortDescription() const
37
+{
38
+ return Localization::WSLCCLI_VolumePruneDesc();
39
+}
40
+
41
+std::wstring VolumePruneCommand::LongDescription() const
42
+{
43
+ return Localization::WSLCCLI_VolumePruneLongDesc();
44
+}
45
+
46
+void VolumePruneCommand::ExecuteInternal(CLIExecutionContext& context) const
47
+{
48
+ context //
49
+ << CreateSession //
50
+ << PruneVolumes;
51
+}
52
+} // namespace wsl::windows::wslc
src/windows/wslc/services/VolumeModel.h
+6
@@ -27,4 +27,10 @@ struct CreateVolumeOptions
27
std::vector<std::pair<std::string, std::string>> Labels{};
28
};
29
30
+struct PruneVolumesResult
31
+{
32
+ std::vector<std::string> PrunedVolumes;
33
+ ULONGLONG SpaceReclaimed{};
34
+};
35
+
36
} // namespace wsl::windows::wslc::models
src/windows/wslc/services/VolumeService.cpp
+39
@@ -12,6 +12,7 @@ Abstract:
12
13
--*/
14
#include "VolumeService.h"
15
+#include "WarningCallback.h"
16
#include <wslutil.h>
17
#include <wslc.h>
18
@@ -81,4 +82,42 @@ wsl::windows::common::wslc_schema::InspectVolume VolumeService::Inspect(models::
82
THROW_IF_FAILED(session.Get()->InspectVolume(name.c_str(), &output));
83
return FromJson<wsl::windows::common::wslc_schema::InspectVolume>(output.get());
84
}
85
+
86
+models::PruneVolumesResult VolumeService::Prune(models::Session& session, bool all, const std::vector<std::pair<std::string, std::string>>& filters)
87
+{
88
+ const bool hasExplicitAll = std::any_of(filters.begin(), filters.end(), [](const auto& f) { return f.first == "all"; });
89
+
90
+ std::vector<WSLCFilter> filterEntries;
91
+ filterEntries.reserve(filters.size() + ((all && !hasExplicitAll) ? 1 : 0));
92
+ if (all && !hasExplicitAll)
93
+ {
94
+ filterEntries.push_back({.Key = "all", .Value = "true"});
95
+ }
96
+
97
+ for (const auto& [key, value] : filters)
98
+ {
99
+ filterEntries.push_back({.Key = key.c_str(), .Value = value.c_str()});
100
+ }
101
+
102
+ auto warningCallback = Microsoft::WRL::Make<WarningCallback>();
103
+ wil::unique_cotaskmem_array_ptr<WSLCVolumeName> volumes;
104
+ ULONGLONG spaceReclaimed = 0;
105
+ THROW_IF_FAILED(session.Get()->PruneVolumes(
106
+ filterEntries.empty() ? nullptr : filterEntries.data(),
107
+ static_cast<ULONG>(filterEntries.size()),
108
+ warningCallback.Get(),
109
+ &volumes,
110
+ volumes.size_address<ULONG>(),
111
+ &spaceReclaimed));
112
+
113
+ models::PruneVolumesResult result;
114
+ result.SpaceReclaimed = spaceReclaimed;
115
+ result.PrunedVolumes.reserve(volumes.size());
116
+ for (auto ptr = volumes.get(), end = volumes.get() + volumes.size(); ptr != end; ++ptr)
117
+ {
118
+ result.PrunedVolumes.emplace_back(*ptr);
119
+ }
120
+
121
+ return result;
122
+}
123
} // namespace wsl::windows::wslc::services
src/windows/wslc/services/VolumeService.h
+1
@@ -24,5 +24,6 @@ struct VolumeService
24
static void Delete(models::Session& session, const std::string& name);
25
static std::vector<WSLCVolumeInformation> List(models::Session& session);
26
static wsl::windows::common::wslc_schema::InspectVolume Inspect(models::Session& session, const std::string& name);
27
+ static models::PruneVolumesResult Prune(models::Session& session, bool all, const std::vector<std::pair<std::string, std::string>>& filters = {});
28
};
29
} // namespace wsl::windows::wslc::services
src/windows/wslc/tasks/VolumeTasks.cpp
+24
@@ -194,4 +194,28 @@ void ListVolumes(CLIExecutionContext& context)
194
THROW_HR(E_UNEXPECTED);
195
}
196
}
197
+
198
+void PruneVolumes(CLIExecutionContext& context)
199
+{
200
+ WI_ASSERT(context.Data.Contains(Data::Session));
201
+ auto& session = context.Data.Get<Data::Session>();
202
+
203
+ const bool all = context.Args.Contains(ArgType::All);
204
+
205
+ std::vector<std::pair<std::string, std::string>> filters;
206
+ for (const auto& value : context.Args.GetAll<ArgType::Filter>())
207
+ {
208
+ filters.push_back(validation::ParseFilter(value));
209
+ }
210
+
211
+ auto result = VolumeService::Prune(session, all, filters);
212
+
213
+ for (const auto& volumeName : result.PrunedVolumes)
214
+ {
215
+ PrintMessage(Localization::WSLCCLI_VolumePruneDeleted(MultiByteToWide(volumeName)));
216
+ }
217
+
218
+ PrintMessage(L"");
219
+ PrintMessage(Localization::WSLCCLI_VolumePruneSpaceReclaimed(wsl::shared::string::FormatBytes(result.SpaceReclaimed)));
220
+}
221
} // namespace wsl::windows::wslc::task
src/windows/wslc/tasks/VolumeTasks.h
+1
@@ -21,4 +21,5 @@ void DeleteVolumes(wsl::windows::wslc::execution::CLIExecutionContext& context);
21
void GetVolumes(wsl::windows::wslc::execution::CLIExecutionContext& context);
22
void InspectVolumes(wsl::windows::wslc::execution::CLIExecutionContext& context);
23
void ListVolumes(wsl::windows::wslc::execution::CLIExecutionContext& context);
24
+void PruneVolumes(wsl::windows::wslc::execution::CLIExecutionContext& context);
25
} // namespace wsl::windows::wslc::task
test/windows/wslc/e2e/WSLCE2EVolumePruneTests.cpp
new
+273
@@ -0,0 +1,273 @@
1
+/*++
2
+
3
+Copyright (c) Microsoft. All rights reserved.
4
+
5
+Module Name:
6
+
7
+ WSLCE2EVolumePruneTests.cpp
8
+
9
+Abstract:
10
+
11
+ This file contains end-to-end tests for the WSLC volume prune command.
12
+--*/
13
+
14
+#include "precomp.h"
15
+#include "windows/Common.h"
16
+#include "WSLCExecutor.h"
17
+#include "WSLCE2EHelpers.h"
18
+
19
+namespace WSLCE2ETests {
20
+using namespace wsl::shared;
21
+
22
+class WSLCE2EVolumePruneTests
23
+{
24
+ WSLC_TEST_CLASS(WSLCE2EVolumePruneTests)
25
+
26
+ TEST_CLASS_SETUP(ClassSetup)
27
+ {
28
+ EnsureImageIsLoaded(DebianImage);
29
+ CleanUpAllTestState();
30
+ return true;
31
+ }
32
+
33
+ TEST_METHOD_SETUP(MethodSetup)
34
+ {
35
+ CleanUpAllTestState();
36
+ return true;
37
+ }
38
+
39
+ TEST_CLASS_CLEANUP(ClassCleanup)
40
+ {
41
+ CleanUpAllTestState();
42
+ EnsureImageIsDeleted(DebianImage);
43
+ return true;
44
+ }
45
+
46
+ WSLC_TEST_METHOD(WSLCE2E_Volume_Prune_HelpCommand)
47
+ {
48
+ const auto result = RunWslc(L"volume prune --help");
49
+ result.Verify({.Stdout = GetHelpMessage(), .Stderr = L"", .ExitCode = 0});
50
+ }
51
+
52
+ WSLC_TEST_METHOD(WSLCE2E_Volume_Prune_NoVolumes)
53
+ {
54
+ // Prune when no volumes exist should succeed and report a reclaimed-space line.
55
+ const auto result = RunWslc(L"volume prune");
56
+ result.Verify({.Stderr = L"", .ExitCode = 0});
57
+
58
+ VERIFY_IS_TRUE(result.StdoutContainsSubstring(L"Total reclaimed space:"));
59
+ }
60
+
61
+ WSLC_TEST_METHOD(WSLCE2E_Volume_Prune_NoAllFlag_PreservesNamedVolumes)
62
+ {
63
+ RunWslc(std::format(L"volume create {}", TestVolumeName)).Verify({.Stderr = L"", .ExitCode = 0});
64
+ VerifyVolumeIsListed(TestVolumeName);
65
+
66
+ auto cleanup = wil::scope_exit([&]() { EnsureVolumeDoesNotExist(TestVolumeName); });
67
+
68
+ const auto result = RunWslc(L"volume prune");
69
+ result.Verify({.Stderr = L"", .ExitCode = 0});
70
+
71
+ auto output = result.GetStdoutLines();
72
+ VERIFY_ARE_EQUAL(2u, output.size());
73
+ VERIFY_ARE_EQUAL(output[0], L"");
74
+ VERIFY_ARE_NOT_EQUAL(std::wstring::npos, output[1].find(L"Total reclaimed space:"));
75
+
76
+ VerifyVolumeIsListed(TestVolumeName);
77
+ }
78
+
79
+ WSLC_TEST_METHOD(WSLCE2E_Volume_Prune_AllFlag_RemovesNamedVolume)
80
+ {
81
+ RunWslc(std::format(L"volume create {}", TestVolumeName)).Verify({.Stderr = L"", .ExitCode = 0});
82
+ VerifyVolumeIsListed(TestVolumeName);
83
+
84
+ auto cleanup = wil::scope_exit([&]() { EnsureVolumeDoesNotExist(TestVolumeName); });
85
+
86
+ const auto result = RunWslc(L"volume prune --all");
87
+ result.Verify({.Stderr = L"", .ExitCode = 0});
88
+
89
+ auto output = result.GetStdoutLines();
90
+ VERIFY_ARE_EQUAL(3u, output.size());
91
+ VERIFY_ARE_NOT_EQUAL(std::wstring::npos, output[0].find(std::format(L"Deleted: {}", TestVolumeName)));
92
+ VERIFY_ARE_EQUAL(output[1], L"");
93
+ VERIFY_ARE_NOT_EQUAL(std::wstring::npos, output[2].find(L"Total reclaimed space:"));
94
+
95
+ VerifyVolumeIsNotListed(TestVolumeName);
96
+ }
97
+
98
+ WSLC_TEST_METHOD(WSLCE2E_Volume_Prune_AllFlag_RemovesMultipleVolumes)
99
+ {
100
+ RunWslc(std::format(L"volume create {}", TestVolumeName)).Verify({.Stderr = L"", .ExitCode = 0});
101
+ RunWslc(std::format(L"volume create {}", TestVolumeName2)).Verify({.Stderr = L"", .ExitCode = 0});
102
+ VerifyVolumeIsListed(TestVolumeName);
103
+ VerifyVolumeIsListed(TestVolumeName2);
104
+
105
+ auto cleanup = wil::scope_exit([&]() {
106
+ EnsureVolumeDoesNotExist(TestVolumeName);
107
+ EnsureVolumeDoesNotExist(TestVolumeName2);
108
+ });
109
+
110
+ const auto result = RunWslc(L"volume prune --all");
111
+ result.Verify({.Stderr = L"", .ExitCode = 0});
112
+
113
+ VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"Deleted: {}", TestVolumeName)));
114
+ VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"Deleted: {}", TestVolumeName2)));
115
+
116
+ VerifyVolumeIsNotListed(TestVolumeName);
117
+ VerifyVolumeIsNotListed(TestVolumeName2);
118
+ }
119
+
120
+ WSLC_TEST_METHOD(WSLCE2E_Volume_Prune_InUseVolume_Preserved)
121
+ {
122
+ RunWslc(std::format(L"volume create {}", TestVolumeName)).Verify({.Stderr = L"", .ExitCode = 0});
123
+ VerifyVolumeIsListed(TestVolumeName);
124
+
125
+ // Start a container that holds the volume open.
126
+ RunWslc(std::format(
127
+ L"container run -d --name {} -v {}:/data {} sleep infinity", WslcContainerName, TestVolumeName, DebianImage.NameAndTag()))
128
+ .Verify({.Stderr = L"", .ExitCode = 0});
129
+
130
+ auto cleanup = wil::scope_exit([&]() {
131
+ EnsureContainerDoesNotExist(WslcContainerName);
132
+ EnsureVolumeDoesNotExist(TestVolumeName);
133
+ });
134
+
135
+ const auto result = RunWslc(L"volume prune --all");
136
+ result.Verify({.Stderr = L"", .ExitCode = 0});
137
+
138
+ VERIFY_IS_FALSE(
139
+ result.StdoutContainsLine(std::format(L"Deleted: {}", TestVolumeName)),
140
+ L"Volume in use by a running container must not be pruned");
141
+
142
+ VerifyVolumeIsListed(TestVolumeName);
143
+ }
144
+
145
+ WSLC_TEST_METHOD(WSLCE2E_Volume_Prune_LabelFilter_PreservesNonMatchingVolume)
146
+ {
147
+ RunWslc(std::format(L"volume create {}", TestVolumeName)).Verify({.Stderr = L"", .ExitCode = 0});
148
+ VerifyVolumeIsListed(TestVolumeName);
149
+
150
+ auto cleanup = wil::scope_exit([&]() { EnsureVolumeDoesNotExist(TestVolumeName); });
151
+
152
+ // A label filter that does not match the volume should preserve it
153
+ const auto filteredPrune = RunWslc(L"volume prune --all --filter label=wslc.test.never=present");
154
+ filteredPrune.Verify({.Stderr = L"", .ExitCode = 0});
155
+ VERIFY_IS_FALSE(
156
+ filteredPrune.StdoutContainsLine(std::format(L"Deleted: {}", TestVolumeName)),
157
+ L"Filtered prune should not have deleted the non-matching volume");
158
+ VerifyVolumeIsListed(TestVolumeName);
159
+
160
+ // Subsequent unfiltered prune --all should still remove it, proving
161
+ // the filter was the reason it survived.
162
+ const auto unfilteredPrune = RunWslc(L"volume prune --all");
163
+ unfilteredPrune.Verify({.Stderr = L"", .ExitCode = 0});
164
+ VERIFY_IS_TRUE(unfilteredPrune.StdoutContainsLine(std::format(L"Deleted: {}", TestVolumeName)));
165
+ VerifyVolumeIsNotListed(TestVolumeName);
166
+ }
167
+
168
+ WSLC_TEST_METHOD(WSLCE2E_Volume_Prune_LabelFilter_MatchingValueIsDeleted)
169
+ {
170
+ RunWslc(std::format(L"volume create --label wslc.test.prune=keep {}", TestVolumeName)).Verify({.Stderr = L"", .ExitCode = 0});
171
+ RunWslc(std::format(L"volume create {}", TestVolumeName2)).Verify({.Stderr = L"", .ExitCode = 0});
172
+ VerifyVolumeIsListed(TestVolumeName);
173
+ VerifyVolumeIsListed(TestVolumeName2);
174
+
175
+ auto cleanup = wil::scope_exit([&]() {
176
+ EnsureVolumeDoesNotExist(TestVolumeName);
177
+ EnsureVolumeDoesNotExist(TestVolumeName2);
178
+ });
179
+
180
+ const auto result = RunWslc(L"volume prune --all --filter label=wslc.test.prune=keep");
181
+ result.Verify({.Stderr = L"", .ExitCode = 0});
182
+
183
+ VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"Deleted: {}", TestVolumeName)));
184
+ VERIFY_IS_FALSE(
185
+ result.StdoutContainsLine(std::format(L"Deleted: {}", TestVolumeName2)),
186
+ L"Volume without the matching label must not be deleted");
187
+
188
+ VerifyVolumeIsNotListed(TestVolumeName);
189
+ VerifyVolumeIsListed(TestVolumeName2);
190
+ }
191
+
192
+ WSLC_TEST_METHOD(WSLCE2E_Volume_Prune_NegatedLabelFilter_PreservesLabeledVolume)
193
+ {
194
+ RunWslc(std::format(L"volume create --label wslc.test.keep=yes {}", TestVolumeName)).Verify({.Stderr = L"", .ExitCode = 0});
195
+ RunWslc(std::format(L"volume create {}", TestVolumeName2)).Verify({.Stderr = L"", .ExitCode = 0});
196
+ VerifyVolumeIsListed(TestVolumeName);
197
+ VerifyVolumeIsListed(TestVolumeName2);
198
+
199
+ auto cleanup = wil::scope_exit([&]() {
200
+ EnsureVolumeDoesNotExist(TestVolumeName);
201
+ EnsureVolumeDoesNotExist(TestVolumeName2);
202
+ });
203
+
204
+ const auto result = RunWslc(L"volume prune --all --filter label!=wslc.test.keep");
205
+ result.Verify({.Stderr = L"", .ExitCode = 0});
206
+
207
+ VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"Deleted: {}", TestVolumeName2)));
208
+ VERIFY_IS_FALSE(
209
+ result.StdoutContainsLine(std::format(L"Deleted: {}", TestVolumeName)),
210
+ L"Labeled volume must be preserved when prune negates that label");
211
+
212
+ VerifyVolumeIsListed(TestVolumeName);
213
+ VerifyVolumeIsNotListed(TestVolumeName2);
214
+ }
215
+
216
+ WSLC_TEST_METHOD(WSLCE2E_Volume_Prune_Filter_MalformedValue)
217
+ {
218
+ const auto result = RunWslc(L"volume prune --filter label");
219
+ result.Verify({.Stdout = GetHelpMessage(), .Stderr = Localization::WSLCCLI_InvalidFilterError(L"label") + L"\r\n", .ExitCode = 1});
220
+ }
221
+
222
+ WSLC_TEST_METHOD(WSLCE2E_Volume_Prune_Filter_InvalidKey)
223
+ {
224
+ const auto result = RunWslc(L"volume prune --filter color=red");
225
+ result.Verify({.Stdout = L"", .Stderr = L"invalid filter 'color'\r\nError code: E_INVALIDARG\r\n", .ExitCode = 1});
226
+ }
227
+
228
+private:
229
+ const TestImage& DebianImage = DebianTestImage();
230
+ const std::wstring TestVolumeName = L"wslc-e2e-volume-prune";
231
+ const std::wstring TestVolumeName2 = L"wslc-e2e-volume-prune-2";
232
+ const std::wstring WslcContainerName = L"wslc-volume-prune-test-container";
233
+
234
+ void CleanUpAllTestState()
235
+ {
236
+ EnsureContainerDoesNotExist(WslcContainerName);
237
+ EnsureVolumeDoesNotExist(TestVolumeName);
238
+ EnsureVolumeDoesNotExist(TestVolumeName2);
239
+ }
240
+
241
+ std::wstring GetHelpMessage() const
242
+ {
243
+ std::wstringstream output;
244
+ output << GetWslcHeader() //
245
+ << GetDescription() //
246
+ << GetUsage() //
247
+ << GetAvailableOptions();
248
+ return output.str();
249
+ }
250
+
251
+ std::wstring GetDescription() const
252
+ {
253
+ return Localization::WSLCCLI_VolumePruneLongDesc() + L"\r\n\r\n";
254
+ }
255
+
256
+ std::wstring GetUsage() const
257
+ {
258
+ return L"Usage: wslc volume prune [<options>]\r\n\r\n";
259
+ }
260
+
261
+ std::wstring GetAvailableOptions() const
262
+ {
263
+ std::wstringstream options;
264
+ options << L"The following options are available:\r\n"
265
+ << L" -a,--all " << Localization::WSLCCLI_VolumePruneAllArgDescription() << L"\r\n"
266
+ << L" -f,--filter " << Localization::WSLCCLI_FilterArgDescription() << L"\r\n"
267
+ << L" --session " << Localization::WSLCCLI_SessionIdArgDescription() << L"\r\n"
268
+ << L" -?,--help " << Localization::WSLCCLI_HelpArgDescription() << L"\r\n"
269
+ << L"\r\n";
270
+ return options.str();
271
+ }
272
+};
273
+} // namespace WSLCE2ETests
test/windows/wslc/e2e/WSLCE2EVolumeTests.cpp
+1
@@ -71,6 +71,7 @@ private:
71
{L"remove", Localization::WSLCCLI_VolumeRemoveDesc()},
72
{L"inspect", Localization::WSLCCLI_VolumeInspectDesc()},
73
{L"list", Localization::WSLCCLI_VolumeListDesc()},
74
+ {L"prune", Localization::WSLCCLI_VolumePruneDesc()},
75
};
76
77
size_t maxLen = 0;