Skip to content

Normalize nested installer paths - #6552

Open
Kaleb Luedtke (Trenly) wants to merge 4 commits into
microsoft:masterfrom
Trenly:fix/6551-normalize-nested-installer-paths
Open

Kaleb Luedtke (Trenly) wants to merge 4 commits into
microsoft:masterfrom
Trenly:fix/6551-normalize-nested-installer-paths

Conversation

@Trenly

@Trenly Kaleb Luedtke (Trenly) commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

📖 Description

Introduces AppInstaller::Utility::NormalizedPath, a std::filesystem::path wrapper that converts UTF-8 inputs to UTF-16 and normalizes directory separators using the platform-preferred separator.

Uses the wrapper for nested installer paths in archive, font, and portable installer workflows, replacing repeated manual calls to make_preferred(). The wrapper is structured so additional normalization can be added later.

🔗 References

Resolves #6551

🔍 Validation

  • Passed: msbuild src\AppInstallerCommonCore\AppInstallerCommonCore.vcxproj /p:Configuration=Debug /p:Platform=x64 /p:SolutionDir=E:\winget-cli\src\ /m:1 /nodeReuse:false /nologo /v:minimal
  • Not completed: msbuild src\AppInstallerCLITests\AppInstallerCLITests.vcxproj /p:Configuration=Debug /p:Platform=x64 /p:SolutionDir=E:\winget-cli\src\ /m:1 /nodeReuse:false /nologo /v:minimal because Visual Studio held a lock on AppInstallerCLICore.idb (C1033). Shared and common library compilation completed successfully before the lock failure.
  • Added NormalizedPath unit coverage for UTF-8 to UTF-16 conversion, preferred separator normalization, std::filesystem::path compatibility, and reassignment.

✅ Checklist

🤖 AI Assistance

  • AI assistance was used and has been disclosed in this PR
  • No AI assistance was used

📋 Issue Type

  • Bug fix
  • Feature
  • Task

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

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@Trenly
Kaleb Luedtke (Trenly) marked this pull request as ready for review September 22, 2026 13:22
@Trenly
Kaleb Luedtke (Trenly) requested a review from a team as a code owner September 22, 2026 13:22
@Trenly
Kaleb Luedtke (Trenly) marked this pull request as draft September 22, 2026 13:23
@Trenly
Kaleb Luedtke (Trenly) marked this pull request as ready for review September 22, 2026 13:23
@github-actions

This comment has been minimized.

for (const auto& nestedInstallerFile : installer.NestedInstallerFiles)
{
const std::filesystem::path& nestedInstallerPath = targetInstallerPath / ConvertToUTF16(nestedInstallerFile.RelativeFilePath);
std::filesystem::path nestedInstallerPath = targetInstallerPath / ConvertToUTF16(nestedInstallerFile.RelativeFilePath);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer that we normalize them centrally; preferably in a way that makes it impossible to get the original version.

One of:

  • Only store as a path and normalize when doing so.
  • Create a wrapper type that effectively forces the above.
  • Make the field private and require access through a method that returns the normalized form.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created the wrapper that forces storage as path and normalizes when doing so

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still requires the call site to do the right thing. With a wrapper, I would replace the type of RelativeFilePath so that the normalization is forced at construction (alternately it could be done lazily through the getter).

Also, your wrapper is far more complex than needed. It doesn't need to be a path, just hold a path.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I'm not fully understanding your suggestion here. Are you saying to make the actual field value in ManifestCommon for RelativeFilePath the NormalizedPath wrapper type?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That, and to make it a simpler wrapper constructed from a string and holding a path that is normalized.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nested installer path is built with the manifest's forward slashes, MsiInstallProduct fails with error 2

2 participants