Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .github/actions/spelling/allow.txt
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ testsettingname
TEXTFORMAT
TEXTINCLUDE
threadpool
TOCTOU
tpl
TRACELOGGING
triaged
Expand Down
6 changes: 6 additions & 0 deletions .github/actions/spelling/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ apfn
apicontract
apiset
appdata
APPEXECLINK
appinstallertest
applic
appname
Expand Down Expand Up @@ -192,6 +193,7 @@ FONTHASH
FORPARSING
foundfr
fsanitize
Fsctl
FULLMUTEX
FULLWIDTH
fundraiser
Expand Down Expand Up @@ -531,6 +533,7 @@ SETTINGMAPPING
sev
sfs
sfsclient
SGNR
SHCONTF
shellapi
SHGDN
Expand Down Expand Up @@ -638,6 +641,7 @@ vns
vscodeignore
vsconfig
vstest
vswhere
waitable
wal
wcex
Expand Down Expand Up @@ -665,6 +669,7 @@ wingetutil
winreg
winrtact
winstring
wintrust
WMI
wmmc
wnd
Expand All @@ -680,6 +685,7 @@ wsb
wsl
wsv
wto
WVT
wwinmain
WZDNCRFJ
xcopy
Expand Down
474 changes: 239 additions & 235 deletions doc/windows/package-manager/winget/returnCodes.md

Large diffs are not rendered by default.

10 changes: 8 additions & 2 deletions src/AppInstallerCLI.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36915.13 d17.14
VisualStudioVersion = 17.14.36915.13
MinimumVisualStudioVersion = 10.0.40219.1
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "AppInstallerCLIPackage", "AppInstallerCLIPackage\AppInstallerCLIPackage.wapproj", "{6AA3791A-0713-4548-A357-87A323E7AC3A}"
ProjectSection(ProjectDependencies) = postProject
Expand Down Expand Up @@ -40,7 +40,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Project", "Project", "{8D53
Get-VcxprojNugetPackageVersions.ps1 = Get-VcxprojNugetPackageVersions.ps1
..\README.md = ..\README.md
..\doc\ReleaseNotes.md = ..\doc\ReleaseNotes.md
..\doc\Settings.md = ..\doc\Settings.md
Update-VcxprojNugetPackageVersions.ps1 = Update-VcxprojNugetPackageVersions.ps1
..\WinGetInProcCom.nuspec = ..\WinGetInProcCom.nuspec
..\WinGetUtil.nuspec = ..\WinGetUtil.nuspec
Expand Down Expand Up @@ -242,6 +241,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "copilot", "copilot", "{B978
..\.github\copilot-instructions.md = ..\.github\copilot-instructions.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{3FF6C881-2548-486E-8D70-7555A90030F5}"
ProjectSection(SolutionItems) = preProject
..\doc\windows\package-manager\winget\returnCodes.md = ..\doc\windows\package-manager\winget\returnCodes.md
..\doc\Settings.md = ..\doc\Settings.md
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.

Should we move all the .mds here?

EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
Expand Down Expand Up @@ -1114,6 +1119,7 @@ Global
{40D7CA7F-EB86-4345-9641-AD27180C559D} = {7C218A3E-9BC8-48FF-B91B-BCACD828C0C9}
{5421394F-5619-4E4B-8923-F3FB30D5EFAD} = {7C218A3E-9BC8-48FF-B91B-BCACD828C0C9}
{B978E358-D2BE-4FA7-A21A-6661F3744DD7} = {8D53D749-D51C-46F8-A162-9371AAA6C2E7}
{3FF6C881-2548-486E-8D70-7555A90030F5} = {8D53D749-D51C-46F8-A162-9371AAA6C2E7}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B6FDB70C-A751-422C-ACD1-E35419495857}
Expand Down
26 changes: 26 additions & 0 deletions src/AppInstallerCLICore/Commands/DebugCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <winrt/Microsoft.Management.Configuration.SetProcessorFactory.h>
#include "AppInstallerDownloader.h"
#include "Sixel.h"
#include <winget/Certificates.h>

using namespace AppInstaller::CLI::Execution;

Expand Down Expand Up @@ -64,6 +65,7 @@ namespace AppInstaller::CLI
std::make_unique<DumpErrorResourceCommand>(FullName()),
std::make_unique<ShowSixelCommand>(FullName()),
std::make_unique<ProgressCommand>(FullName()),
std::make_unique<GetSignerCommand>(FullName()),
std::make_unique<LogViewerTestCommand>(FullName()),
std::make_unique<DebugDscResourceCommand>(FullName()),
});
Expand Down Expand Up @@ -370,6 +372,30 @@ namespace AppInstaller::CLI
}
}

std::vector<Argument> GetSignerCommand::GetArguments() const
{
return {
Argument{ "file", 'f', Args::Type::Manifest, Resource::String::SourceListUpdatedNever, ArgumentType::Positional },
};
}

Resource::LocString GetSignerCommand::ShortDescription() const
{
return Utility::LocIndString("Get signer information"sv);
}

Resource::LocString GetSignerCommand::LongDescription() const
{
return Utility::LocIndString("Gets the signing information for a given path."sv);
}

void GetSignerCommand::ExecuteInternal(Execution::Context& context) const
{
std::string subject = Certificates::GetAuthenticodeSubject(context.Args.GetArg(Args::Type::Manifest));

context.Reporter.Info() << "Subject: " << subject << std::endl;
}

// ── LogViewerTestCommand ─────────────────────────────────────────────────────

#define WINGET_DEBUG_LOG_VIEWER_FOLLOW Args::Type::Force
Expand Down
14 changes: 14 additions & 0 deletions src/AppInstallerCLICore/Commands/DebugCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,20 @@ namespace AppInstaller::CLI
void ExecuteInternal(Execution::Context& context) const override;
};

// Invokes signing information collection for a path.
struct GetSignerCommand final : public Command
{
GetSignerCommand(std::string_view parent) : Command("get-signer", {}, parent) {}

std::vector<Argument> GetArguments() const override;

Resource::LocString ShortDescription() const override;
Resource::LocString LongDescription() const override;

protected:
void ExecuteInternal(Execution::Context& context) const override;
};

// Tests the log viewer extension by emitting logs that exercise all channels, levels, subchannels,
// continuation lines, long lines, and optionally a streaming follow mode.
struct LogViewerTestCommand final : public Command
Expand Down
134 changes: 133 additions & 1 deletion src/AppInstallerCLICore/Commands/ErrorCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include "AppInstallerErrors.h"
#include "VTSupport.h"

#include <filesystem>

namespace AppInstaller::CLI
{
namespace
Expand All @@ -23,12 +25,123 @@ namespace AppInstaller::CLI
info << std::endl;
info << error.GetDescription() << std::endl;
}

struct ErrorGroup
{
std::string_view Name;
WORD MinCode; // HRESULT_CODE, inclusive
WORD MaxCode; // HRESULT_CODE, inclusive
};

// Groups matching the sections in the published returnCodes.md documentation.
constexpr ErrorGroup s_errorGroups[] =
{
{ "General Errors", 0x0001, 0x00FF },
{ "Install errors.", 0x0100, 0x01FF },
{ "Check for package installed status", 0x0200, 0x02FF },
{ "Configuration Errors", 0xC000, 0xC0FF },
{ "Configuration Processor Errors", 0xC100, 0xC1FF },
};

constexpr std::string_view s_uncategorizedGroupName = "Uncategorized";

// Writes the markdown table for a group of errors to the given stream.
void WriteMarkdownGroup(std::ostream& out, std::string_view groupName, std::vector<const Errors::HResultInformation*>& errors)
{
if (errors.empty())
{
return;
}

std::sort(errors.begin(), errors.end(),
[](const Errors::HResultInformation* a, const Errors::HResultInformation* b) { return HRESULT_CODE(a->Value()) < HRESULT_CODE(b->Value()); });

out << "\n## " << groupName << "\n\n";
out << "| Hex | Decimal | Symbol | Description |\n";
out << "|-------------|-------------|-------------|-------------|\n";

for (const auto* error : errors)
{
HRESULT hr = error->Value();
char hexBuf[11];
sprintf_s(hexBuf, "0x%08X", static_cast<uint32_t>(hr));

out << "| " << hexBuf
<< " | " << static_cast<int32_t>(hr)
<< " | " << error->Symbol()
<< " | " << error->GetDescription()
<< " |\n";
}
}

void OutputErrorMarkdown(Execution::Context& context)
{
auto allErrors = Errors::GetWinGetErrors();

// Categorize each error into its group; the last slot holds uncategorized errors.
static constexpr size_t s_errorGroupsCount = ARRAYSIZE(s_errorGroups);
std::vector<std::vector<const Errors::HResultInformation*>> groupedErrors(s_errorGroupsCount + 1);

for (const auto& error : allErrors)
{
HRESULT hr = error->Value();
WORD code = static_cast<WORD>(HRESULT_CODE(hr));

bool placed = false;
for (size_t i = 0; i < s_errorGroupsCount; ++i)
{
if (code >= s_errorGroups[i].MinCode && code <= s_errorGroups[i].MaxCode)
{
groupedErrors[i].push_back(error.get());
placed = true;
break;
}
}

if (!placed)
{
groupedErrors[s_errorGroupsCount].push_back(error.get());
}
}

std::filesystem::path outputPath{ Utility::ConvertToUTF16(context.Args.GetArg(Execution::Args::Type::OutputFile)) };
std::ofstream out{ outputPath };
THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_OPEN_FAILED), !out);

std::time_t now = std::time(nullptr);
std::tm tm{};
localtime_s(&tm, &now);
char dateBuf[11];
strftime(dateBuf, sizeof(dateBuf), "%m/%d/%Y", &tm);

out <<
"---\n"
"title: WinGet HRESULT Codes\n"
"description: WinGet return codes and their meanings\n"
"ms.date: " << dateBuf << "\n"
"ms.topic: article\n"
"ms.localizationpriority: low\n"
"---\n"
"\n"
"> [!NOTE]\n"
"> This file is generated by running: winget error --output <file>\n"
"\n"
"# Return Codes\n";

for (size_t i = 0; i < ARRAYSIZE(s_errorGroups); ++i)
{
WriteMarkdownGroup(out, s_errorGroups[i].Name, groupedErrors[i]);
}

WriteMarkdownGroup(out, s_uncategorizedGroupName, groupedErrors[s_errorGroupsCount]);
}
}

std::vector<Argument> ErrorCommand::GetArguments() const
{
return {
Argument{ Execution::Args::Type::ErrorInput, Resource::String::ErrorInputArgumentDescription, ArgumentType::Positional, true },
Argument{ Execution::Args::Type::ErrorInput, Resource::String::ErrorInputArgumentDescription, ArgumentType::Positional },
Argument{ Execution::Args::Type::OutputFile, Resource::String::ErrorOutputFileArgumentDescription, ArgumentType::Standard },
};
}

Expand All @@ -42,8 +155,27 @@ namespace AppInstaller::CLI
return { Resource::String::ErrorCommandLongDescription };
}

void ErrorCommand::ValidateArgumentsInternal(Execution::Args& execArgs) const
{
if (execArgs.Contains(Execution::Args::Type::OutputFile) && execArgs.Contains(Execution::Args::Type::ErrorInput))
{
throw CommandException(Resource::String::ErrorOutputFileConflictsWithInput);
}

if (!execArgs.Contains(Execution::Args::Type::OutputFile) && !execArgs.Contains(Execution::Args::Type::ErrorInput))
{
throw CommandException(Resource::String::ErrorRequiresInputOrOutputFile);
}
}

void ErrorCommand::ExecuteInternal(Execution::Context& context) const
{
if (context.Args.Contains(Execution::Args::Type::OutputFile))
{
OutputErrorMarkdown(context);
return;
}

std::string input{ context.Args.GetArg(Execution::Args::Type::ErrorInput) };

const char* begin = input.c_str();
Expand Down
1 change: 1 addition & 0 deletions src/AppInstallerCLICore/Commands/ErrorCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace AppInstaller::CLI
Resource::LocString LongDescription() const override;

protected:
void ValidateArgumentsInternal(Execution::Args& execArgs) const override;
void ExecuteInternal(Execution::Context& context) const override;
};
}
33 changes: 33 additions & 0 deletions src/AppInstallerCLICore/ConfigurationDynamicRuntimeFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,10 +341,12 @@ namespace AppInstaller::CLI::ConfigurationRemoting
{
winrt::hstring dscExecutablePathPropertyName = ToHString(PropertyName::DscExecutablePath);
std::optional<winrt::hstring> dscExecutablePath = m_dynamicFactory->GetFactoryMapValue(dscExecutablePathPropertyName);
bool usingFoundPath = false;

if (!dscExecutablePath)
{
dscExecutablePath = m_dynamicFactory->Lookup(ToHString(PropertyName::FoundDscExecutablePath));
usingFoundPath = true;
}

if (dscExecutablePath->empty())
Expand All @@ -355,6 +357,37 @@ namespace AppInstaller::CLI::ConfigurationRemoting
}

json["processorPath"] = Utility::ConvertToUTF8(dscExecutablePath.value());

if (usingFoundPath)
{
// FoundDscExecutablePathHash/IsAlias are computed on the remote side alongside FoundDscExecutablePath.
winrt::hstring pathHash = m_dynamicFactory->Lookup(ToHString(PropertyName::FoundDscExecutablePathHash));
if (!pathHash.empty())
{
json["processorPathHash"] = Utility::ConvertToUTF8(pathHash);
}

winrt::hstring pathIsAlias = m_dynamicFactory->Lookup(ToHString(PropertyName::FoundDscExecutablePathIsAlias));
if (!pathIsAlias.empty())
{
json["processorPathIsAlias"] = (pathIsAlias == L"true");
}
}
else
{
// DscExecutablePathHash/IsAlias are set locally via the audit block.
auto pathHash = m_dynamicFactory->GetFactoryMapValue(ToHString(PropertyName::DscExecutablePathHash));
if (pathHash)
{
json["processorPathHash"] = Utility::ConvertToUTF8(pathHash.value());
}

auto pathIsAlias = m_dynamicFactory->GetFactoryMapValue(ToHString(PropertyName::DscExecutablePathIsAlias));
if (pathIsAlias)
{
json["processorPathIsAlias"] = (pathIsAlias.value() == L"true");
}
}
}

Json::StreamWriterBuilder writerBuilder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -381,8 +381,11 @@ namespace AppInstaller::CLI::ConfigurationRemoting
case PropertyName::FoundDscExecutablePath: return L"FoundDscExecutablePath";
case PropertyName::DiagnosticTraceEnabled: return L"DiagnosticTraceEnabled";
case PropertyName::FindDscStateMachine: return L"FindDscStateMachine";
case PropertyName::DscExecutablePathHash: return L"DscExecutablePathHash";
case PropertyName::DscExecutablePathIsAlias: return L"DscExecutablePathIsAlias";
case PropertyName::FoundDscExecutablePathHash: return L"FoundDscExecutablePathHash";
case PropertyName::FoundDscExecutablePathIsAlias: return L"FoundDscExecutablePathIsAlias";
}

THROW_HR(E_UNEXPECTED);
}
}
Expand Down
Loading
Loading