Skip to content
Draft
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/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ SRL
srs
Standalone
startswith
streambuf
strtoull
subdir
subkey
Expand Down
2 changes: 2 additions & 0 deletions src/AppInstallerCLICore/AppInstallerCLICore.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@
<ItemGroup>
<ClInclude Include="Argument.h" />
<ClInclude Include="ChannelStreams.h" />
<ClInclude Include="COMContext.h" />
<ClInclude Include="Command.h" />
<ClInclude Include="Commands\CompleteCommand.h" />
<ClInclude Include="Commands\ExperimentalCommand.h" />
Expand Down Expand Up @@ -221,6 +222,7 @@
<ClInclude Include="Workflows\WorkflowBase.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="COMContext.cpp" />
<ClCompile Include="Commands\ImportCommand.cpp" />
<ClCompile Include="PackageCollection.cpp" />
<ClCompile Include="Argument.cpp" />
Expand Down
6 changes: 6 additions & 0 deletions src/AppInstallerCLICore/AppInstallerCLICore.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@
<ClInclude Include="ExecutionContext.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="COMContext.h">
<Filter>Public</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
Expand Down Expand Up @@ -271,6 +274,9 @@
<ClCompile Include="Commands\ImportCommand.cpp">
<Filter>Commands</Filter>
</ClCompile>
<ClCompile Include="COMContext.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="PropertySheet.props" />
Expand Down
35 changes: 35 additions & 0 deletions src/AppInstallerCLICore/COMContext.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "pch.h"
#include "COMContext.h"

namespace AppInstaller
{

NullStream::NullStream()
{
m_nullOut.reset(new std::ostream(&m_nullStreamBuf));
m_nullIn.reset(new std::istream(&m_nullStreamBuf));
}

void COMContext::BeginProgress()
{
m_comProgressCallback(ReportType::BeginProgress, 0, 0, ProgressType::None, m_executionStage);
};

void COMContext::OnProgress(uint64_t current, uint64_t maximum, ProgressType progressType)
{
m_comProgressCallback(ReportType::Progressing, current, maximum, progressType, m_executionStage);
}

void COMContext::EndProgress(bool)
{
m_comProgressCallback(ReportType::EndProgress, 0, 0, ProgressType::None, m_executionStage);
};

void COMContext::SetExecutionStage(CLI::Workflow::ExecutionStage executionStage, bool)
{
m_executionStage = executionStage;
m_comProgressCallback(ReportType::ExecutionPhaseUpdate, 0, 0, ProgressType::None, m_executionStage);
}
}
69 changes: 69 additions & 0 deletions src/AppInstallerCLICore/COMContext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
#include "pch.h"
#include "..\AppInstallerCommonCore\Public\AppInstallerProgress.h"
#include "ExecutionContext.h"
#include "Workflows/WorkflowBase.h"

namespace AppInstaller
{
enum class ReportType: uint32_t
{
ExecutionPhaseUpdate,
BeginProgress,
Progressing,
EndProgress,
};

class NullStreamBuf : public std::streambuf {};

struct NullStream
{
NullStream();

~NullStream() = default;

protected:
NullStreamBuf m_nullStreamBuf;
std::unique_ptr<std::ostream> m_nullOut;
std::unique_ptr<std::istream> m_nullIn;
};

typedef std::function<void(ReportType reportType, uint64_t current, uint64_t maximum, ProgressType progressType, CLI::Workflow::ExecutionStage executionPhase)> ProgressCallBackFunction;

// NullStream constructs the Stream parameters for Context constructor
// Hence, NullStream should always precede Context in base class order of COMContext's inheritance
struct COMContext : IProgressSink, NullStream, CLI::Execution::Context
{
// When no Console streams need involvement, construct NullStreams instead to pass to Context
COMContext() : NullStream(), CLI::Execution::Context(*m_nullOut, *m_nullIn)
{
Reporter.SetProgressSink(this);
}

COMContext(std::ostream& out, std::istream& in) : CLI::Execution::Context(out, in)
{
Reporter.SetProgressSink(this);
}

~COMContext() = default;

// IProgressSink
void BeginProgress() override;
void OnProgress(uint64_t current, uint64_t maximum, ProgressType type) override;
void EndProgress(bool) override;

//Execution::Context
void SetExecutionStage(CLI::Workflow::ExecutionStage executionPhase, bool);

void SetProgressCallbackFunction(ProgressCallBackFunction&& f)
{
m_comProgressCallback = std::move(f);
}

private:
CLI::Workflow::ExecutionStage m_executionStage = CLI::Workflow::ExecutionStage::Initial;
ProgressCallBackFunction m_comProgressCallback;
};
}
55 changes: 55 additions & 0 deletions src/AppInstallerCLICore/Command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -770,4 +770,59 @@ namespace AppInstaller::CLI

return arguments;
}

int Execute(Execution::Context& context, std::unique_ptr<Command>& command)
{
try
{
if (!Settings::User().GetWarnings().empty())
{
context.Reporter.Warn() << Resource::String::SettingsWarnings << std::endl;
}

command->Execute(context);
}
// Exceptions that may occur in the process of executing an arbitrary command
catch (const wil::ResultException& re)
{
// Even though they are logged at their source, log again here for completeness.
Logging::Telemetry().LogException(command->FullName(), "wil::ResultException", re.what());
context.Reporter.Error() <<
Resource::String::UnexpectedErrorExecutingCommand << ' ' << std::endl <<
GetUserPresentableMessage(re) << std::endl;
return re.GetErrorCode();
}
catch (const winrt::hresult_error& hre)
{
std::string message = GetUserPresentableMessage(hre);
Logging::Telemetry().LogException(command->FullName(), "winrt::hresult_error", message);
context.Reporter.Error() <<
Resource::String::UnexpectedErrorExecutingCommand << ' ' << std::endl <<
message << std::endl;
return hre.code();
}
catch (const std::exception& e)
{
Logging::Telemetry().LogException(command->FullName(), "std::exception", e.what());
context.Reporter.Error() <<
Resource::String::UnexpectedErrorExecutingCommand << ' ' << std::endl <<
GetUserPresentableMessage(e) << std::endl;
return APPINSTALLER_CLI_ERROR_COMMAND_FAILED;
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
Logging::Telemetry().LogException(command->FullName(), "unknown", {});
context.Reporter.Error() <<
Resource::String::UnexpectedErrorExecutingCommand << " ???"_liv << std::endl;
return APPINSTALLER_CLI_ERROR_COMMAND_FAILED;
}

if (SUCCEEDED(context.GetTerminationHR()))
{
Logging::Telemetry().LogCommandSuccess(command->FullName());
}

return context.GetTerminationHR();
}
}
2 changes: 2 additions & 0 deletions src/AppInstallerCLICore/Command.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,6 @@ namespace AppInstaller::CLI

return result;
}

int Execute(Execution::Context& context, std::unique_ptr<Command>& command);
}
54 changes: 2 additions & 52 deletions src/AppInstallerCLICore/Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "ExecutionContext.h"
#include "Workflows/WorkflowBase.h"
#include <winget/UserSettings.h>
#include "Commands/InstallCommand.h"

using namespace winrt;
using namespace winrt::Windows::Foundation;
Expand Down Expand Up @@ -115,63 +116,12 @@ namespace AppInstaller::CLI
return APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS;
}

try
{
if (!Settings::User().GetWarnings().empty())
{
context.Reporter.Warn() << Resource::String::SettingsWarnings << std::endl;
}

command->Execute(context);
}
// Exceptions that may occur in the process of executing an arbitrary command
catch (const wil::ResultException& re)
{
// Even though they are logged at their source, log again here for completeness.
Logging::Telemetry().LogException(command->FullName(), "wil::ResultException", re.what());
context.Reporter.Error() <<
Resource::String::UnexpectedErrorExecutingCommand << ' ' << std::endl <<
GetUserPresentableMessage(re) << std::endl;
return re.GetErrorCode();
}
catch (const winrt::hresult_error& hre)
{
std::string message = GetUserPresentableMessage(hre);
Logging::Telemetry().LogException(command->FullName(), "winrt::hresult_error", message);
context.Reporter.Error() <<
Resource::String::UnexpectedErrorExecutingCommand << ' ' << std::endl <<
message << std::endl;
return hre.code();
}
catch (const std::exception& e)
{
Logging::Telemetry().LogException(command->FullName(), "std::exception", e.what());
context.Reporter.Error() <<
Resource::String::UnexpectedErrorExecutingCommand << ' ' << std::endl <<
GetUserPresentableMessage(e) << std::endl;
return APPINSTALLER_CLI_ERROR_COMMAND_FAILED;
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
Logging::Telemetry().LogException(command->FullName(), "unknown", {});
context.Reporter.Error() <<
Resource::String::UnexpectedErrorExecutingCommand << " ???"_liv << std::endl;
return APPINSTALLER_CLI_ERROR_COMMAND_FAILED;
}

if (SUCCEEDED(context.GetTerminationHR()))
{
Logging::Telemetry().LogCommandSuccess(command->FullName());
}

return context.GetTerminationHR();
return Execute(context, command);
}
// End of the line exceptions that are not ever expected.
// Telemetry cannot be reliable beyond this point, so don't let these happen.
catch (...)
{
return APPINSTALLER_CLI_ERROR_INTERNAL_ERROR;
}

}
14 changes: 14 additions & 0 deletions src/AppInstallerCLICore/ExecutionContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,18 @@ namespace AppInstaller::CLI::Execution
m_isTerminated = true;
m_terminationHR = hr;
}

void Context::SetExecutionStage(Workflow::ExecutionStage stage, bool allowBackward)
{
if (m_executionStage == stage)
{
return;
}
else if (m_executionStage > stage && !allowBackward)
{
THROW_HR_MSG(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), "Reporting ExecutionStage to an earlier Stage without allowBackward as true");
}

m_executionStage = stage;
}
}
3 changes: 3 additions & 0 deletions src/AppInstallerCLICore/ExecutionContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ namespace AppInstaller::CLI::Execution
WI_ClearAllFlags(m_flags, flags);
}

virtual void SetExecutionStage(Workflow::ExecutionStage stage, bool);

#ifndef AICLI_DISABLE_TEST_HOOKS
// Enable tests to override behavior
virtual bool ShouldExecuteWorkflowTask(const Workflow::WorkflowTask&) { return true; }
Expand All @@ -112,5 +114,6 @@ namespace AppInstaller::CLI::Execution
HRESULT m_terminationHR = S_OK;
size_t m_CtrlSignalCount = 0;
ContextFlag m_flags = ContextFlag::None;
Workflow::ExecutionStage m_executionStage = Workflow::ExecutionStage::Initial;
};
}
7 changes: 0 additions & 7 deletions src/AppInstallerCLICore/ExecutionContextData.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ namespace AppInstaller::CLI::Execution
InstallerArgs,
CompletionData,
InstalledPackageVersion,
ExecutionStage,
UninstallString,
PackageFamilyNames,
ProductCodes,
Expand Down Expand Up @@ -137,12 +136,6 @@ namespace AppInstaller::CLI::Execution
using value_t = std::shared_ptr<Repository::IPackageVersion>;
};

template <>
struct DataMapping<Data::ExecutionStage>
{
using value_t = Workflow::ExecutionStage;
};

template <>
struct DataMapping<Data::UninstallString>
{
Expand Down
20 changes: 19 additions & 1 deletion src/AppInstallerCLICore/ExecutionReporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ namespace AppInstaller::CLI::Execution
m_in(inStream),
m_progressBar(std::in_place, outStream, IsVTEnabled()),
m_spinner(std::in_place, outStream, IsVTEnabled())
{}
{
SetProgressSink(this);
}

Reporter::~Reporter()
{
Expand Down Expand Up @@ -120,6 +122,22 @@ namespace AppInstaller::CLI::Execution
m_progressBar->ShowProgress(current, maximum, type);
}
}

void Reporter::BeginProgress()
{
GetBasicOutputStream() << VirtualTerminal::Cursor::Visibility::DisableShow;
ShowIndefiniteProgress(true);
};

void Reporter::EndProgress(bool hideProgressWhenDone)
{
ShowIndefiniteProgress(false);
if (m_progressBar)
{
m_progressBar->EndProgress(hideProgressWhenDone);
}
GetBasicOutputStream() << VirtualTerminal::Cursor::Visibility::EnableShow;
};

void Reporter::SetProgressCallback(ProgressCallback* callback)
{
Expand Down
Loading