winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

DebugCommand.cpp (18196B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 
      5 #if _DEBUG
      6 #include "DebugCommand.h"
      7 #include <winrt/Microsoft.Management.Configuration.h>
      8 #include <winrt/Microsoft.Management.Configuration.SetProcessorFactory.h>
      9 #include "AppInstallerDownloader.h"
     10 #include "Sixel.h"
     11 
     12 using namespace AppInstaller::CLI::Execution;
     13 
     14 namespace AppInstaller::CLI
     15 {
     16     namespace
     17     {
     18         std::string MakeInterfaceNameAttribute(std::wstring_view name)
     19         {
     20             std::string result = Utility::ConvertToUTF8(name);
     21             Utility::FindAndReplace(result, "<", "&lt;");
     22             Utility::FindAndReplace(result, ">", "&gt;");
     23             return result;
     24         }
     25 
     26         std::string MakeIIDAttribute(const winrt::guid& guid)
     27         {
     28             std::string result;
     29             wchar_t buffer[256];
     30 
     31             if (StringFromGUID2(guid, buffer, ARRAYSIZE(buffer)))
     32             {
     33                 result = AppInstaller::Utility::ConvertToUTF8(buffer);
     34                 result = result.substr(1, result.length() - 2);
     35             }
     36             else
     37             {
     38                 result = "error";
     39             }
     40 
     41             return result;
     42         }
     43 
     44         template <typename Interface>
     45         void OutputProxyStubInterfaceRegistration(Execution::Context& context)
     46         {
     47             context.Reporter.Info() << "<Interface Name=\"" << MakeInterfaceNameAttribute(winrt::name_of<Interface>()) << "\" InterfaceId=\"" << MakeIIDAttribute(winrt::guid_of<Interface>()) << "\" />" << std::endl;
     48         }
     49 
     50         template <typename Interface>
     51         void OutputIIDMapping(Execution::Context& context)
     52         {
     53             context.Reporter.Info() << Utility::ConvertToUTF8(winrt::name_of<Interface>()) << " == " << winrt::guid_of<Interface>() << std::endl;
     54         }
     55     }
     56 
     57     std::vector<std::unique_ptr<Command>> DebugCommand::GetCommands() const
     58     {
     59         return InitializeFromMoveOnly<std::vector<std::unique_ptr<Command>>>({
     60             std::make_unique<DumpProxyStubRegistrationsCommand>(FullName()),
     61             std::make_unique<DumpInterestingIIDsCommand>(FullName()),
     62             std::make_unique<DumpErrorResourceCommand>(FullName()),
     63             std::make_unique<ShowSixelCommand>(FullName()),
     64             std::make_unique<ProgressCommand>(FullName()),
     65         });
     66     }
     67 
     68     Resource::LocString DebugCommand::ShortDescription() const
     69     {
     70         return Utility::LocIndString("Debug only dev commands"sv);
     71     }
     72 
     73     Resource::LocString DebugCommand::LongDescription() const
     74     {
     75         return Utility::LocIndString("Commands that are useful in debugging and development."sv);
     76     }
     77 
     78     void DebugCommand::ExecuteInternal(Execution::Context& context) const
     79     {
     80         OutputHelp(context.Reporter);
     81     }
     82 
     83     Resource::LocString DumpProxyStubRegistrationsCommand::ShortDescription() const
     84     {
     85         return Utility::LocIndString("Dump proxy-stub registrations"sv);
     86     }
     87 
     88     Resource::LocString DumpProxyStubRegistrationsCommand::LongDescription() const
     89     {
     90         return Utility::LocIndString("Dump proxy-stub registrations for WinRT interfaces to be place in the manifest."sv);
     91     }
     92 
     93     void DumpProxyStubRegistrationsCommand::ExecuteInternal(Execution::Context& context) const
     94     {
     95         OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::ConfigurationUnit>>(context);
     96         OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::ConfigurationSet>>(context);
     97         OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::ConfigurationConflict>>(context);
     98         OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::ConfigurationParameter>>(context);
     99         OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::IConfigurationUnitSettingDetails>>(context);
    100         OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::ConfigurationConflictSetting>>(context);
    101         OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::GetConfigurationUnitDetailsResult>>(context);
    102         OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::ApplyConfigurationUnitResult>>(context);
    103         OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::TestConfigurationUnitResult>>(context);
    104         OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::IApplyGroupMemberSettingsResult>>(context);
    105         OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::ITestSettingsResult>>(context);
    106         OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::ConfigurationEnvironment>>(context);
    107         OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::IConfigurationUnitProcessorDetails>>(context);
    108         OutputProxyStubInterfaceRegistration<winrt::Microsoft::Management::Configuration::IConfigurationUnitProcessorDetails2>(context);
    109         OutputProxyStubInterfaceRegistration<winrt::Microsoft::Management::Configuration::IConfigurationUnitProcessorDetails3>(context);
    110         OutputProxyStubInterfaceRegistration<winrt::Microsoft::Management::Configuration::IGetAllSettingsConfigurationUnitProcessor>(context);
    111         OutputProxyStubInterfaceRegistration<winrt::Microsoft::Management::Configuration::IGetAllUnitsConfigurationUnitProcessor>(context);
    112         OutputProxyStubInterfaceRegistration<winrt::Microsoft::Management::Configuration::IFindUnitProcessorsSetProcessor>(context);
    113         OutputProxyStubInterfaceRegistration<winrt::Microsoft::Management::Configuration::IConfigurationStatics2>(context);
    114         OutputProxyStubInterfaceRegistration<winrt::Microsoft::Management::Configuration::IConfigurationStatics3>(context);
    115         OutputProxyStubInterfaceRegistration<winrt::Microsoft::Management::Configuration::SetProcessorFactory::IPwshConfigurationSetProcessorFactoryProperties>(context);
    116 
    117         // TODO: Fix the layering inversion created by the COM deployment API (probably in order to operate winget.exe against the COM server).
    118         //       Then this code can just have a CppWinRT reference to the deployment API and spit out the interface registrations just like for configuration.
    119         HMODULE module = nullptr;
    120         if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast<LPCWSTR>(&MakeInterfaceNameAttribute), &module))
    121         {
    122             return;
    123         }
    124 
    125         // TODO: Have a PRIVATE export from WindowsPackageManager that returns a set of names and IIDs to include from the Deployment API surface
    126     }
    127 
    128     Resource::LocString DumpInterestingIIDsCommand::ShortDescription() const
    129     {
    130         return Utility::LocIndString("Dump some IIDs"sv);
    131     }
    132 
    133     Resource::LocString DumpInterestingIIDsCommand::LongDescription() const
    134     {
    135         return Utility::LocIndString("Dump some IIDs that might be useful."sv);
    136     }
    137 
    138     void DumpInterestingIIDsCommand::ExecuteInternal(Execution::Context& context) const
    139     {
    140         OutputIIDMapping<winrt::Microsoft::Management::Configuration::IConfigurationStatics>(context);
    141         OutputIIDMapping<winrt::Microsoft::Management::Configuration::IConfigurationStatics2>(context);
    142         OutputIIDMapping<winrt::Microsoft::Management::Configuration::IConfigurationStatics3>(context);
    143     }
    144 
    145     Resource::LocString DumpErrorResourceCommand::ShortDescription() const
    146     {
    147         return Utility::LocIndString("Dump error resources"sv);
    148     }
    149 
    150     Resource::LocString DumpErrorResourceCommand::LongDescription() const
    151     {
    152         return Utility::LocIndString("Dump the error information as resources."sv);
    153     }
    154 
    155     void DumpErrorResourceCommand::ExecuteInternal(Execution::Context& context) const
    156     {
    157         auto info = context.Reporter.Info();
    158 
    159         //  <data name="InstallFlowReturnCodeInstallInProgress" xml:space="preserve">
    160         //    <value>Another installation is already in progress. Try again later.</value>
    161         //  </data>
    162         for (const auto& error : Errors::GetWinGetErrors())
    163         {
    164             info <<
    165                 "  <data name=\"" << error->Symbol() << "\" xml:space=\"preserve\">\n"
    166                 "    <value>" << error->GetDescription() << "</value>\n"
    167                 "  </data>" << std::endl;
    168         }
    169     }
    170 
    171 #define WINGET_DEBUG_SIXEL_FILE Args::Type::Manifest
    172 #define WINGET_DEBUG_SIXEL_ASPECT_RATIO Args::Type::AcceptPackageAgreements
    173 #define WINGET_DEBUG_SIXEL_TRANSPARENT Args::Type::AcceptSourceAgreements
    174 #define WINGET_DEBUG_SIXEL_COLOR_COUNT Args::Type::ConfigurationAcceptWarning
    175 #define WINGET_DEBUG_SIXEL_WIDTH Args::Type::AdminSettingEnable
    176 #define WINGET_DEBUG_SIXEL_HEIGHT Args::Type::AllowReboot
    177 #define WINGET_DEBUG_SIXEL_STRETCH Args::Type::AllVersions
    178 #define WINGET_DEBUG_SIXEL_REPEAT Args::Type::Name
    179 #define WINGET_DEBUG_SIXEL_OUT_FILE Args::Type::BlockingPin
    180 
    181     std::vector<Argument> ShowSixelCommand::GetArguments() const
    182     {
    183         return {
    184             Argument{ "file", 'f', WINGET_DEBUG_SIXEL_FILE, Resource::String::SourceListUpdatedNever, ArgumentType::Positional },
    185             Argument{ "aspect-ratio", 'a', WINGET_DEBUG_SIXEL_ASPECT_RATIO, Resource::String::SourceListUpdatedNever, ArgumentType::Standard },
    186             Argument{ "transparent", 't', WINGET_DEBUG_SIXEL_TRANSPARENT, Resource::String::SourceListUpdatedNever, ArgumentType::Flag },
    187             Argument{ "color-count", 'c', WINGET_DEBUG_SIXEL_COLOR_COUNT, Resource::String::SourceListUpdatedNever, ArgumentType::Standard },
    188             Argument{ "width", 'w', WINGET_DEBUG_SIXEL_WIDTH, Resource::String::SourceListUpdatedNever, ArgumentType::Standard },
    189             Argument{ "height", 'h', WINGET_DEBUG_SIXEL_HEIGHT, Resource::String::SourceListUpdatedNever, ArgumentType::Standard },
    190             Argument{ "stretch", 's', WINGET_DEBUG_SIXEL_STRETCH, Resource::String::SourceListUpdatedNever, ArgumentType::Flag },
    191             Argument{ "repeat", 'r', WINGET_DEBUG_SIXEL_REPEAT, Resource::String::SourceListUpdatedNever, ArgumentType::Flag },
    192             Argument{ "out-file", 'o', WINGET_DEBUG_SIXEL_OUT_FILE, Resource::String::SourceListUpdatedNever, ArgumentType::Standard },
    193         };
    194     }
    195 
    196     Resource::LocString ShowSixelCommand::ShortDescription() const
    197     {
    198         return Utility::LocIndString("Output an image with sixels"sv);
    199     }
    200 
    201     Resource::LocString ShowSixelCommand::LongDescription() const
    202     {
    203         return Utility::LocIndString("Outputs an image from a file using sixel format."sv);
    204     }
    205 
    206     void ShowSixelCommand::ExecuteInternal(Execution::Context& context) const
    207     {
    208         using namespace VirtualTerminal;
    209         std::unique_ptr<Sixel::Image> sixelImagePtr;
    210 
    211         std::string imageUrl{ context.Args.GetArg(WINGET_DEBUG_SIXEL_FILE) };
    212 
    213         if (Utility::IsUrlRemote(imageUrl))
    214         {
    215             auto imageStream = std::make_unique<std::stringstream>();
    216             ProgressCallback emptyCallback;
    217             Utility::DownloadToStream(imageUrl, *imageStream, Utility::DownloadType::Manifest, emptyCallback);
    218 
    219             sixelImagePtr = std::make_unique<Sixel::Image>(*imageStream, Manifest::IconFileTypeEnum::Unknown);
    220         }
    221         else
    222         {
    223             sixelImagePtr = std::make_unique<Sixel::Image>(Utility::ConvertToUTF16(imageUrl));
    224         }
    225 
    226         Sixel::Image& sixelImage = *sixelImagePtr.get();
    227 
    228         if (context.Args.Contains(WINGET_DEBUG_SIXEL_ASPECT_RATIO))
    229         {
    230             switch (context.Args.GetArg(WINGET_DEBUG_SIXEL_ASPECT_RATIO)[0])
    231             {
    232             case '1':
    233                 sixelImage.AspectRatio(Sixel::AspectRatio::OneToOne);
    234                 break;
    235             case '2':
    236                 sixelImage.AspectRatio(Sixel::AspectRatio::TwoToOne);
    237                 break;
    238             case '3':
    239                 sixelImage.AspectRatio(Sixel::AspectRatio::ThreeToOne);
    240                 break;
    241             case '5':
    242                 sixelImage.AspectRatio(Sixel::AspectRatio::FiveToOne);
    243                 break;
    244             }
    245         }
    246 
    247         sixelImage.Transparency(context.Args.Contains(WINGET_DEBUG_SIXEL_TRANSPARENT));
    248 
    249         if (context.Args.Contains(WINGET_DEBUG_SIXEL_COLOR_COUNT))
    250         {
    251             sixelImage.ColorCount(std::stoul(std::string{ context.Args.GetArg(WINGET_DEBUG_SIXEL_COLOR_COUNT) }));
    252         }
    253 
    254         if (context.Args.Contains(WINGET_DEBUG_SIXEL_WIDTH) && context.Args.Contains(WINGET_DEBUG_SIXEL_HEIGHT))
    255         {
    256             sixelImage.RenderSizeInCells(
    257                 std::stoul(std::string{ context.Args.GetArg(WINGET_DEBUG_SIXEL_WIDTH) }),
    258                 std::stoul(std::string{ context.Args.GetArg(WINGET_DEBUG_SIXEL_HEIGHT) }));
    259         }
    260 
    261         sixelImage.StretchSourceToFill(context.Args.Contains(WINGET_DEBUG_SIXEL_STRETCH));
    262 
    263         sixelImage.UseRepeatSequence(context.Args.Contains(WINGET_DEBUG_SIXEL_REPEAT));
    264 
    265         if (context.Args.Contains(WINGET_DEBUG_SIXEL_OUT_FILE))
    266         {
    267             std::ofstream stream{ Utility::ConvertToUTF16(context.Args.GetArg(WINGET_DEBUG_SIXEL_OUT_FILE)) };
    268             stream << sixelImage.Render().Get();
    269         }
    270         else
    271         {
    272             OutputStream stream = context.Reporter.GetOutputStream(Reporter::Level::Info);
    273             stream.ClearFormat();
    274             sixelImage.RenderTo(stream);
    275 
    276             // Force a new line to show entire image
    277             stream << std::endl;
    278         }
    279     }
    280 
    281 #define WINGET_DEBUG_PROGRESS_SIXEL Args::Type::Manifest
    282 #define WINGET_DEBUG_PROGRESS_DISABLED Args::Type::GatedVersion
    283 #define WINGET_DEBUG_PROGRESS_HIDE Args::Type::AcceptPackageAgreements
    284 #define WINGET_DEBUG_PROGRESS_TIME Args::Type::AcceptSourceAgreements
    285 #define WINGET_DEBUG_PROGRESS_MESSAGE Args::Type::ConfigurationAcceptWarning
    286 #define WINGET_DEBUG_PROGRESS_PERCENT Args::Type::AllowReboot
    287 #define WINGET_DEBUG_PROGRESS_POST Args::Type::AllVersions
    288 
    289     std::vector<Argument> ProgressCommand::GetArguments() const
    290     {
    291         return {
    292             Argument{ "sixel", 's', WINGET_DEBUG_PROGRESS_SIXEL, Resource::String::SourceListUpdatedNever, ArgumentType::Flag },
    293             Argument{ "disabled", 'd', WINGET_DEBUG_PROGRESS_DISABLED, Resource::String::SourceListUpdatedNever, ArgumentType::Flag },
    294             Argument{ "hide", 'h', WINGET_DEBUG_PROGRESS_HIDE, Resource::String::SourceListUpdatedNever, ArgumentType::Flag },
    295             Argument{ "time", 't', WINGET_DEBUG_PROGRESS_TIME, Resource::String::SourceListUpdatedNever, ArgumentType::Standard },
    296             Argument{ "message", 'm', WINGET_DEBUG_PROGRESS_MESSAGE, Resource::String::SourceListUpdatedNever, ArgumentType::Standard },
    297             Argument{ "percent", 'p', WINGET_DEBUG_PROGRESS_PERCENT, Resource::String::SourceListUpdatedNever, ArgumentType::Flag },
    298             Argument{ "post", 0, WINGET_DEBUG_PROGRESS_POST, Resource::String::SourceListUpdatedNever, ArgumentType::Standard },
    299         };
    300     }
    301 
    302     Resource::LocString ProgressCommand::ShortDescription() const
    303     {
    304         return Utility::LocIndString("Show progress"sv);
    305     }
    306 
    307     Resource::LocString ProgressCommand::LongDescription() const
    308     {
    309         return Utility::LocIndString("Show progress with various controls to emulate different behaviors."sv);
    310     }
    311 
    312     void ProgressCommand::ExecuteInternal(Execution::Context& context) const
    313     {
    314         if (context.Args.Contains(WINGET_DEBUG_PROGRESS_SIXEL))
    315         {
    316             context.Reporter.SetStyle(Settings::VisualStyle::Sixel);
    317         }
    318 
    319         if (context.Args.Contains(WINGET_DEBUG_PROGRESS_DISABLED))
    320         {
    321             context.Reporter.SetStyle(Settings::VisualStyle::Disabled);
    322         }
    323 
    324         auto progress = context.Reporter.BeginAsyncProgress(context.Args.Contains(WINGET_DEBUG_PROGRESS_HIDE));
    325 
    326         if (context.Args.Contains(WINGET_DEBUG_PROGRESS_MESSAGE))
    327         {
    328             progress->Callback().SetProgressMessage(context.Args.GetArg(WINGET_DEBUG_PROGRESS_MESSAGE));
    329         }
    330 
    331         bool sendProgress = context.Args.Contains(WINGET_DEBUG_PROGRESS_PERCENT);
    332 
    333         UINT timeInSeconds = 3600;
    334         if (context.Args.Contains(WINGET_DEBUG_PROGRESS_TIME))
    335         {
    336             timeInSeconds = std::stoul(std::string{ context.Args.GetArg(WINGET_DEBUG_PROGRESS_TIME) });
    337         }
    338 
    339         UINT ticks = timeInSeconds * 10;
    340         for (UINT i = 0; i < ticks; ++i)
    341         {
    342             if (sendProgress)
    343             {
    344                 progress->Callback().OnProgress(i, ticks, ProgressType::Bytes);
    345             }
    346 
    347             if (progress->Callback().IsCancelledBy(CancelReason::Any))
    348             {
    349                 sendProgress = false;
    350                 break;
    351             }
    352 
    353             std::this_thread::sleep_for(100ms);
    354         }
    355 
    356         if (sendProgress)
    357         {
    358             progress->Callback().OnProgress(ticks, ticks, ProgressType::Bytes);
    359         }
    360 
    361         progress.reset();
    362 
    363         if (context.Args.Contains(WINGET_DEBUG_PROGRESS_POST))
    364         {
    365             context.Reporter.Info() << context.Args.GetArg(WINGET_DEBUG_PROGRESS_POST) << std::endl;
    366         }
    367     }
    368 }
    369 
    370 #endif