Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ba81b75
Add hourly upstream sync workflow for feature/wsl-for-apps
kvega005 Mar 5, 2026
50f9ce0
Remove upstream sync workflow
kvega005 Mar 5, 2026
c55426c
Merge branch 'microsoft:master' into master
kvega005 Mar 23, 2026
0055811
Merge branch 'microsoft:master' into master
kvega005 Apr 1, 2026
de88707
Merge branch 'microsoft:master' into master
kvega005 Apr 12, 2026
f16fc61
Merge branch 'microsoft:master' into master
kvega005 Apr 30, 2026
da31dd2
Merge branch 'microsoft:master' into master
kvega005 May 1, 2026
b95f237
Merge branch 'microsoft:master' into master
kvega005 May 1, 2026
2ae93aa
Merge branch 'microsoft:master' into master
kvega005 May 6, 2026
f805f05
Merge branch 'microsoft:master' into master
kvega005 May 7, 2026
f2b4090
Merge branch 'microsoft:master' into master
kvega005 May 13, 2026
07445a2
Merge branch 'microsoft:master' into master
kvega005 May 15, 2026
9a29435
Merge branch 'microsoft:master' into master
kvega005 May 18, 2026
a3416ea
Change image filters to use generic kvp
kvega005 May 18, 2026
cd3b60b
Redo image filters
kvega005 May 18, 2026
4689fe3
Fix merge
kvega005 May 18, 2026
6492adb
fix build
kvega005 May 19, 2026
761184f
Merge branch 'master' into imageFilters
kvega005 May 19, 2026
31e7510
Address feedback
kvega005 May 22, 2026
7de50a4
Merge branch 'imageFilters' of https://github.com/kvega005/WSL into i…
kvega005 May 22, 2026
42cd70a
Merge branch 'master' into imageFilters
kvega005 May 22, 2026
bd5dde6
add test
kvega005 May 27, 2026
1a4d58e
Merge branch 'imageFilters' of https://github.com/kvega005/WSL into i…
kvega005 May 27, 2026
1c23529
Address feedback
kvega005 May 28, 2026
32bd2e3
Remove unused struct
kvega005 May 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 9 additions & 35 deletions src/windows/service/inc/wslc.idl
Original file line number Diff line number Diff line change
Expand Up @@ -151,14 +151,11 @@ typedef struct _WSLCImageInformation
typedef enum _WSLCListImagesFlags
{
WSLCListImagesFlagsNone = 0,
WSLCListImagesFlagsAll = 1, // Show all images (default hides intermediate images)
WSLCListImagesFlagsDigests = 2, // Include digest information
WSLCListImagesFlagsDanglingTrue = 4, // Show only dangling images (untagged)
WSLCListImagesFlagsDanglingFalse = 8, // Show only non-dangling images (tagged)
// Note: If neither dangling flag is set, no dangling filter is passed (default: both).
WSLCListImagesFlagsAll = 1, // Show all images (default hides intermediate images)
WSLCListImagesFlagsDigests = 2, // Include digest information
} WSLCListImagesFlags;

cpp_quote("#define WSLCListImagesFlagsValid (WSLCListImagesFlagsAll | WSLCListImagesFlagsDigests | WSLCListImagesFlagsDanglingTrue | WSLCListImagesFlagsDanglingFalse)")
cpp_quote("#define WSLCListImagesFlagsValid (WSLCListImagesFlagsAll | WSLCListImagesFlagsDigests)")

cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCListImagesFlags);")

Expand All @@ -181,15 +178,12 @@ typedef KeyValuePair WSLCFilter;
typedef KeyValuePairInformation WSLCLabelInformation;
typedef KeyValuePairInformation WSLCDriverOptionInformation;

typedef struct _WSLCListImageOptions
typedef struct _WSLCListImagesOptions
{
DWORD Flags; // WSLCListImagesFlags (can combine with bitwise OR)
[unique] LPCSTR Reference; // Filter by reference (name[:tag])
[unique] LPCSTR Before; // Filter: show images created before this image
[unique] LPCSTR Since; // Filter: show images created since this image
[unique, size_is(LabelsCount)] const WSLCLabel* Labels;
ULONG LabelsCount;
} WSLCListImageOptions;
[unique, size_is(FiltersCount)] const WSLCFilter* Filters;
ULONG FiltersCount;
} WSLCListImagesOptions;

typedef enum _WSLCProcessFlags
{
Expand Down Expand Up @@ -667,26 +661,6 @@ typedef struct _WSLCPruneContainersResults
ULONGLONG SpaceReclaimed;
} WSLCPruneContainersResults;

typedef enum _WSLCPruneImagesFlags
{
WSLCPruneImagesFlagsNone = 0,
WSLCPruneImagesFlagsDanglingTrue = 1, // Only prune dangling (untagged) images.
WSLCPruneImagesFlagsDanglingFalse = 2, // Prune all images not used by any container.
// Note: If neither dangling flag is set, no dangling filter is passed (Docker defaults to dangling-only).
} WSLCPruneImagesFlags;

cpp_quote("#define WSLCPruneImagesFlagsValid (WSLCPruneImagesFlagsDanglingTrue | WSLCPruneImagesFlagsDanglingFalse)")

cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCPruneImagesFlags);")

typedef struct _WSLCPruneImagesOptions
{
DWORD Flags; // WSLCPruneImagesFlags
ULONGLONG Until;
[unique, size_is(LabelsCount)] const WSLCPruneLabelFilter* Labels;
ULONG LabelsCount;
} WSLCPruneImagesOptions;

typedef enum _WSLCListContainersFlags
{
WSLCListContainersFlagsNone = 0,
Expand Down Expand Up @@ -744,11 +718,11 @@ interface IWSLCSession : IUnknown
HRESULT LoadImage([in] WSLCHandle ImageHandle, [in, unique] IProgressCallback* ProgressCallback, [in] ULONGLONG ContentLength);
Comment thread
OneBlue marked this conversation as resolved.
HRESULT ImportImage([in] WSLCHandle ImageHandle, [in] LPCSTR ImageName, [in, unique] IProgressCallback* ProgressCallback, [in] ULONGLONG ContentLength);
HRESULT SaveImage([in] WSLCHandle OutputHandle, [in] LPCSTR ImageNameOrID, [in, unique] IProgressCallback * ProgressCallback, [in, unique, system_handle(sh_event)] HANDLE CancelEvent);
HRESULT ListImages([in, unique] const WSLCListImageOptions* Options, [out, size_is(, *Count)] WSLCImageInformation** Images, [out] ULONG* Count);
HRESULT ListImages([in, unique] const WSLCListImagesOptions* Options, [out, size_is(, *Count)] WSLCImageInformation** Images, [out] ULONG* Count);
HRESULT DeleteImage([in] const WSLCDeleteImageOptions* Options, [out, size_is(, *Count)] WSLCDeletedImageInformation** DeletedImages, [out] ULONG* Count);
HRESULT TagImage([in] const WSLCTagImageOptions* Options);
HRESULT InspectImage([in] LPCSTR ImageNameOrId, [out] LPSTR* Output);
HRESULT PruneImages([in, unique] const WSLCPruneImagesOptions* Options, [out, size_is(, *DeletedImagesCount)] WSLCDeletedImageInformation** DeletedImages, [out] ULONG* DeletedImagesCount, [out] ULONGLONG* SpaceReclaimed);
HRESULT PruneImages([in, unique, size_is(FiltersCount)] const WSLCFilter* Filters, [in] ULONG FiltersCount, [out, size_is(, *DeletedImagesCount)] WSLCDeletedImageInformation** DeletedImages, [out] ULONG* DeletedImagesCount, [out] ULONGLONG* SpaceReclaimed);
Comment thread
kvega005 marked this conversation as resolved.

// Container management.
HRESULT CreateContainer([in] const WSLCContainerOptions* Options, [out] IWSLCContainer** Container);
Expand Down
8 changes: 2 additions & 6 deletions src/windows/wslc/services/ImageService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,15 +299,11 @@ void ImageService::Save(wsl::windows::wslc::models::Session& session, const std:

wsl::windows::wslc::models::PruneImagesResult ImageService::Prune(wsl::windows::wslc::models::Session& session, bool all)
{
WSLCPruneImagesOptions options{};
if (all)
{
WI_SetFlag(options.Flags, WSLCPruneImagesFlagsDanglingFalse);
}
WSLCFilter filter{.Key = "dangling", .Value = all ? "false" : "true"};

wil::unique_cotaskmem_array_ptr<WSLCDeletedImageInformation> deletedImages;
ULONGLONG spaceReclaimed = 0;
THROW_IF_FAILED(session.Get()->PruneImages(&options, &deletedImages, deletedImages.size_address<ULONG>(), &spaceReclaimed));
THROW_IF_FAILED(session.Get()->PruneImages(&filter, 1, &deletedImages, deletedImages.size_address<ULONG>(), &spaceReclaimed));

wsl::windows::wslc::models::PruneImagesResult result;
result.SpaceReclaimed = spaceReclaimed;
Expand Down
80 changes: 6 additions & 74 deletions src/windows/wslcsession/DockerHTTPClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,47 +53,6 @@ bool IsResponseChunked(const http::response_parser<http::buffer_body>::value_typ

return true;
}
template <typename TFilters>
nlohmann::json PruneFiltersToJson(const TFilters& filters)
{
nlohmann::json j;

if constexpr (requires { filters.dangling; })
{
if (filters.dangling.has_value())
{
j["dangling"] = nlohmann::json::array({filters.dangling.value() ? "true" : "false"});
}
}

if constexpr (requires { filters.all; })
{
if (filters.all.has_value() && filters.all.value())
{
j["all"] = nlohmann::json::array({"true"});
}
}

if constexpr (requires { filters.until; })
{
if (filters.until.has_value())
{
j["until"] = nlohmann::json::array({std::to_string(filters.until.value())});
}
}

if (!filters.presentLabels.empty())
{
j["label"] = filters.presentLabels;
}

if (!filters.absentLabels.empty())
{
j["label!"] = filters.absentLabels;
}

return j;
}

} // namespace

Expand Down Expand Up @@ -231,43 +190,16 @@ std::string DockerHTTPClient::Authenticate(const std::string& serverAddress, con
return response.IdentityToken.value_or("");
}

std::vector<docker_schema::Image> DockerHTTPClient::ListImages(bool all, bool digests, const ListImagesFilters& filters)
std::vector<docker_schema::Image> DockerHTTPClient::ListImages(bool all, bool digests, const std::map<std::string, std::vector<std::string>>& filters)
{
auto url = URL::Create("/images/json");

url.SetParameter("all", all);
url.SetParameter("digests", digests);

// Build filters JSON if any filters are set
nlohmann::json filtersJson;

if (filters.reference.has_value())
{
filtersJson["reference"] = nlohmann::json::array({filters.reference.value()});
}

if (filters.before.has_value())
{
filtersJson["before"] = nlohmann::json::array({filters.before.value()});
}

if (filters.since.has_value())
{
filtersJson["since"] = nlohmann::json::array({filters.since.value()});
}

if (filters.dangling.has_value())
{
filtersJson["dangling"] = nlohmann::json::array({filters.dangling.value() ? "true" : "false"});
}

if (!filters.labels.empty())
{
filtersJson["label"] = filters.labels;
}

if (!filtersJson.empty())
if (!filters.empty())
{
nlohmann::json filtersJson = filters;
url.SetParameter("filters", filtersJson.dump());
}

Expand Down Expand Up @@ -295,13 +227,13 @@ std::pair<uint32_t, wil::unique_socket> DockerHTTPClient::SaveImage(const std::s
return {response.result_int(), std::move(socket)};
}

docker_schema::PruneImageResult DockerHTTPClient::PruneImages(const PruneImagesFilters& filters)
docker_schema::PruneImageResult DockerHTTPClient::PruneImages(const std::map<std::string, std::vector<std::string>>& filters)
{
auto url = URL::Create("/images/prune");

auto filtersJson = PruneFiltersToJson(filters);
if (!filtersJson.empty())
if (!filters.empty())
{
nlohmann::json filtersJson = filters;
url.SetParameter("filters", filtersJson.dump());
}

Expand Down
22 changes: 3 additions & 19 deletions src/windows/wslcsession/DockerHTTPClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,35 +152,19 @@ class DockerHTTPClient
common::docker_schema::Network InspectNetwork(const std::string& Name);

// Image management.
struct ListImagesFilters
{
std::optional<std::string> reference;
std::optional<std::string> before;
std::optional<std::string> since;
std::optional<bool> dangling;
std::vector<std::string> labels;
};

struct PruneImagesFilters
{
std::optional<bool> dangling;
std::optional<std::uint64_t> until;
std::vector<std::string> presentLabels;
std::vector<std::string> absentLabels;
};

std::unique_ptr<HTTPRequestContext> PullImage(
const std::string& Repo, const std::optional<std::string>& tagOrDigest, const std::optional<std::string>& registryAuth = std::nullopt);
std::unique_ptr<HTTPRequestContext> ImportImage(const std::string& Repo, const std::string& Tag, uint64_t ContentLength);
std::unique_ptr<HTTPRequestContext> LoadImage(uint64_t ContentLength);
void TagImage(const std::string& Id, const std::string& Repo, const std::string& Tag);
std::unique_ptr<HTTPRequestContext> PushImage(const std::string& ImageName, const std::optional<std::string>& tag, const std::string& registryAuth);
std::string Authenticate(const std::string& serverAddress, const std::string& username, const std::string& password);
std::vector<common::docker_schema::Image> ListImages(bool all = false, bool digests = false, const ListImagesFilters& filters = {});
std::vector<common::docker_schema::Image> ListImages(
bool all = false, bool digests = false, const std::map<std::string, std::vector<std::string>>& filters = {});
common::docker_schema::InspectImage InspectImage(const std::string& NameOrId);
std::vector<common::docker_schema::DeletedImage> DeleteImage(const char* Image, bool Force, bool NoPrune); // Image can be ID or Repo:Tag.
std::pair<uint32_t, wil::unique_socket> SaveImage(const std::string& NameOrId);
common::docker_schema::PruneImageResult PruneImages(const PruneImagesFilters& filters = {});
common::docker_schema::PruneImageResult PruneImages(const std::map<std::string, std::vector<std::string>>& filters = {});

// Exec.
common::docker_schema::CreateExecResponse CreateExec(const std::string& Container, const common::docker_schema::CreateExec& Request);
Expand Down
Loading