-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add resume
command and support saving the argument state.
#3508
Merged
Merged
Changes from all commits
Commits
Show all changes
50 commits
Select commit
Hold shift + click to select a range
291ded4
save work
c6adb1a
it builds!
952a799
save work
2ed8d2c
add checkpoint manager
166b843
retrieve args from index
cbc34db
save work
4786194
clean up index functions
8982105
resolve merge conflicts
0f5ce84
add initial unit tests
e3786aa
save tests
940599f
fix e2E test and cleanup
ba3bcb6
fix CLIcore filter
dace07e
resolve merge conflicts and fix spelling
8d9a3b4
save work
e15a142
savework
22840a5
save work
35b772f
it builds
9f7f3f5
capture context data
e939e90
simplify work and update tests
a757d8c
fix spelling
3cf3fb7
remove EF check
ed47dd1
try again
3bca5d4
fix client Version
525bf1c
add table
623e26c
save work
f0d86b6
save notes
5ef5dce
template example
3775cb0
save work
44ebf0b
save work
bbee38e
save work
b0e64a6
save work
754cb8f
fix tests
5a91681
clean up
c536e20
resolve merge conflicts
6076097
fix tests and fix spelling
5107a85
fix path for checkpoints directory
16ac252
remove all references to index
1022bc2
actually fix e2e tests
e04f6bb
rename checkpointRecord to checkpointDatabase
ryfu-msft 38d3f83
save work
ryfu-msft 1d1250b
address rest of comments
ryfu-msft e57f23e
resolve merge conflicts
ryfu-msft d73ef7d
fix path
ryfu-msft 3540ba0
Merge branch 'master' of https://github.com/ryfu-msft/winget-cli into…
ryfu-msft ae2dda0
fix path recursive call
ryfu-msft a3e72c7
minor fix
ryfu-msft c133d52
fix resume e2e test
ryfu-msft 8a2da5d
respond to PR feedback
ryfu-msft 792c465
fix error code
ryfu-msft a8f0ced
resolve merge conflicts
ryfu-msft File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -233,6 +233,7 @@ https | |
HWND | ||
Hyperlink | ||
IAppx | ||
ICheckpoint | ||
IConfiguration | ||
icu | ||
IDX | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
#include "pch.h" | ||
#include "CheckpointManager.h" | ||
#include "Command.h" | ||
#include "ExecutionContextData.h" | ||
#include <AppInstallerRuntime.h> | ||
|
||
namespace AppInstaller::Checkpoints | ||
{ | ||
using namespace AppInstaller::CLI; | ||
using namespace AppInstaller::Repository::Microsoft; | ||
using namespace AppInstaller::Repository::SQLite; | ||
|
||
// This checkpoint name is reserved for the starting checkpoint which captures the automatic metadata. | ||
constexpr std::string_view s_AutomaticCheckpoint = "automatic"sv; | ||
constexpr std::string_view s_CheckpointsFileName = "checkpoints.db"sv; | ||
|
||
std::filesystem::path CheckpointManager::GetCheckpointDatabasePath(const std::string_view& resumeId, bool createCheckpointDirectory) | ||
{ | ||
const auto checkpointsDirectory = Runtime::GetPathTo(Runtime::PathName::CheckpointsLocation) / resumeId; | ||
|
||
if (createCheckpointDirectory) | ||
{ | ||
if (!std::filesystem::exists(checkpointsDirectory)) | ||
{ | ||
AICLI_LOG(Repo, Info, << "Creating checkpoint database directory: " << checkpointsDirectory); | ||
std::filesystem::create_directories(checkpointsDirectory); | ||
} | ||
else | ||
{ | ||
THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_CANNOT_MAKE), !std::filesystem::is_directory(checkpointsDirectory)); | ||
} | ||
} | ||
|
||
auto recordPath = checkpointsDirectory / s_CheckpointsFileName; | ||
return recordPath; | ||
} | ||
|
||
CheckpointManager::CheckpointManager() | ||
{ | ||
GUID resumeId; | ||
std::ignore = CoCreateGuid(&resumeId); | ||
m_resumeId = Utility::ConvertGuidToString(resumeId); | ||
const auto& checkpointDatabasePath = GetCheckpointDatabasePath(m_resumeId, true); | ||
m_checkpointDatabase = CheckpointDatabase::CreateNew(checkpointDatabasePath.u8string()); | ||
} | ||
|
||
CheckpointManager::CheckpointManager(const std::string& resumeId) | ||
{ | ||
m_resumeId = resumeId; | ||
const auto& checkpointDatabasePath = GetCheckpointDatabasePath(m_resumeId); | ||
m_checkpointDatabase = CheckpointDatabase::Open(checkpointDatabasePath.u8string()); | ||
} | ||
|
||
void CheckpointManager::CreateAutomaticCheckpoint(CLI::Execution::Context& context) | ||
{ | ||
CheckpointDatabase::IdType startCheckpointId = m_checkpointDatabase->AddCheckpoint(s_AutomaticCheckpoint); | ||
Checkpoint<AutomaticCheckpointData> automaticCheckpoint{ m_checkpointDatabase, startCheckpointId }; | ||
|
||
automaticCheckpoint.Set(AutomaticCheckpointData::ClientVersion, {}, AppInstaller::Runtime::GetClientVersion()); | ||
|
||
const auto& executingCommand = context.GetExecutingCommand(); | ||
if (executingCommand != nullptr) | ||
{ | ||
automaticCheckpoint.Set(AutomaticCheckpointData::Command, {}, std::string{ executingCommand->FullName() }); | ||
} | ||
|
||
const auto& argTypes = context.Args.GetTypes(); | ||
for (auto type : argTypes) | ||
{ | ||
const auto& argument = std::to_string(static_cast<int>(type)); | ||
auto argumentType = Argument::ForType(type).Type(); | ||
|
||
if (argumentType == ArgumentType::Flag) | ||
{ | ||
automaticCheckpoint.Set(AutomaticCheckpointData::Arguments, argument, {}); | ||
} | ||
else | ||
{ | ||
const auto& values = *context.Args.GetArgs(type); | ||
automaticCheckpoint.SetMany(AutomaticCheckpointData::Arguments, argument, values); | ||
} | ||
} | ||
} | ||
|
||
void LoadCommandArgsFromAutomaticCheckpoint(CLI::Execution::Context& context, Checkpoint<AutomaticCheckpointData>& automaticCheckpoint) | ||
{ | ||
for (const auto& fieldName : automaticCheckpoint.GetFieldNames(AutomaticCheckpointData::Arguments)) | ||
{ | ||
// Command arguments are represented as integer strings in the checkpoint record. | ||
Execution::Args::Type type = static_cast<Execution::Args::Type>(std::stoi(fieldName)); | ||
auto argumentType = Argument::ForType(type).Type(); | ||
if (argumentType == ArgumentType::Flag) | ||
{ | ||
context.Args.AddArg(type); | ||
} | ||
else | ||
{ | ||
const auto& values = automaticCheckpoint.GetMany(AutomaticCheckpointData::Arguments, fieldName); | ||
for (const auto& value : values) | ||
{ | ||
context.Args.AddArg(type, value); | ||
} | ||
} | ||
} | ||
} | ||
|
||
std::optional<Checkpoint<AutomaticCheckpointData>> CheckpointManager::GetAutomaticCheckpoint() | ||
{ | ||
const auto& checkpointIds = m_checkpointDatabase->GetCheckpointIds(); | ||
if (checkpointIds.empty()) | ||
{ | ||
return {}; | ||
} | ||
|
||
CheckpointDatabase::IdType automaticCheckpointId = checkpointIds.back(); | ||
return Checkpoint<AutomaticCheckpointData>{ m_checkpointDatabase, automaticCheckpointId }; | ||
} | ||
|
||
Checkpoint<CLI::Execution::Data> CheckpointManager::CreateCheckpoint(std::string_view checkpointName) | ||
{ | ||
CheckpointDatabase::IdType checkpointId = m_checkpointDatabase->AddCheckpoint(checkpointName); | ||
Checkpoint<CLI::Execution::Data> checkpoint{ m_checkpointDatabase, checkpointId }; | ||
return checkpoint; | ||
} | ||
|
||
std::vector<Checkpoint<CLI::Execution::Data>> CheckpointManager::GetCheckpoints() | ||
{ | ||
auto checkpointIds = m_checkpointDatabase->GetCheckpointIds(); | ||
if (checkpointIds.empty()) | ||
{ | ||
return {}; | ||
} | ||
|
||
// Remove the last checkpoint (automatic) | ||
checkpointIds.pop_back(); | ||
|
||
std::vector<Checkpoint<CLI::Execution::Data>> checkpoints; | ||
for (const auto& checkpointId : checkpointIds) | ||
{ | ||
checkpoints.emplace_back(Checkpoint<CLI::Execution::Data>{ m_checkpointDatabase, checkpointId }); | ||
} | ||
|
||
return checkpoints; | ||
} | ||
|
||
void CheckpointManager::CleanUpDatabase() | ||
{ | ||
if (m_checkpointDatabase) | ||
{ | ||
m_checkpointDatabase.reset(); | ||
} | ||
|
||
if (!m_resumeId.empty()) | ||
{ | ||
const auto& checkpointDatabasePath = GetCheckpointDatabasePath(m_resumeId); | ||
if (std::filesystem::exists(checkpointDatabasePath)) | ||
{ | ||
const auto& checkpointDatabaseParentDirectory = checkpointDatabasePath.parent_path(); | ||
AICLI_LOG(CLI, Info, << "Deleting Checkpoint database directory: " << checkpointDatabaseParentDirectory); | ||
std::filesystem::remove_all(checkpointDatabaseParentDirectory); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
#pragma once | ||
#include "ExecutionContextData.h" | ||
#include "ExecutionContext.h" | ||
#include "Public/winget/Checkpoint.h" | ||
#include <guiddef.h> | ||
|
||
namespace AppInstaller::Repository::Microsoft | ||
{ | ||
struct CheckpointDatabase; | ||
} | ||
|
||
namespace AppInstaller::Checkpoints | ||
{ | ||
// Reads the command arguments from the automatic checkpoint and populates the context. | ||
void LoadCommandArgsFromAutomaticCheckpoint(CLI::Execution::Context& context, Checkpoint<AutomaticCheckpointData>& automaticCheckpoint); | ||
|
||
// Owns the lifetime of a checkpoint data base and creates the checkpoints. | ||
struct CheckpointManager | ||
{ | ||
// Constructor that generates a new resume id and creates the checkpoint database. | ||
CheckpointManager(); | ||
|
||
// Constructor that loads the resume id and opens an existing checkpoint database. | ||
CheckpointManager(const std::string& resumeId); | ||
|
||
~CheckpointManager() = default; | ||
|
||
// Gets the file path of the checkpoint database. | ||
static std::filesystem::path GetCheckpointDatabasePath(const std::string_view& resumeId, bool createCheckpointDirectory = false); | ||
|
||
// Gets the automatic checkpoint. | ||
std::optional<Checkpoint<AutomaticCheckpointData>> GetAutomaticCheckpoint(); | ||
|
||
// Creates an automatic checkpoint using the provided context. | ||
void CreateAutomaticCheckpoint(CLI::Execution::Context& context); | ||
|
||
// Gets all context data checkpoints. | ||
std::vector<Checkpoint<CLI::Execution::Data>> GetCheckpoints(); | ||
|
||
// Creates a new context data checkpoint. | ||
Checkpoint<CLI::Execution::Data> CreateCheckpoint(std::string_view checkpointName); | ||
|
||
// Cleans up the checkpoint database. | ||
void CleanUpDatabase(); | ||
|
||
private: | ||
std::string m_resumeId; | ||
std::shared_ptr<AppInstaller::Repository::Microsoft::CheckpointDatabase> m_checkpointDatabase; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In
GetAutomaticCheckpoint
you check for empty, but not here.