-
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
Configure export command #4434
Configure export command #4434
Conversation
This comment has been minimized.
This comment has been minimized.
|
||
namespace AppInstaller::CLI | ||
{ | ||
struct ConfigureExportCommand final : public Command |
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.
Just curious if there is a design preference here. The subcommands for other areas like pinning are contained within the parent file. For example, PinRemoveCommand
is contained in PinCommand.h
and SettingsExportCommand
is contained in SettingsCommand.h
. Is there a reason that all the configuration sub commands wouldn't be included in ConfigureCommand.h
?
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.
My 2🪙: This isn't large enough to warrant a new file, which is to say that if a subcommand were itself rather complex I think it would be ok to break it out (or if it had its own subcommands, etc.)
winrt::hstring description; | ||
if (dependantUnit.has_value()) | ||
{ | ||
description = L"Configure " + dependantUnit.value().Identifier(); |
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.
I believe it would be best if the descriptions were localized, since it's not a field which performs an action. A user exporting a configuration on a machine would likely prefer their descriptions to be in their preferred locale in the event they need to manually modify it
} | ||
|
||
void CreateConfigurationProcessor(Context& context) | ||
{ | ||
auto progressScope = context.Reporter.BeginAsyncProgress(true); | ||
progressScope->Callback().SetProgressMessage(Resource::String::ConfigurationInitializing()); | ||
|
||
ConfigurationProcessor processor{ CreateConfigurationSetProcessorFactory(context)}; | ||
ConfigurationProcessor processor{ anon::CreateConfigurationSetProcessorFactory(context)}; |
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.
Is there a reason for explicitly naming the anonymous namespace? I haven't seen this done before
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.
I've learned that anonymous namespace does not output type information into the PDB in a way that debuggers (at least VS and WinDBG) can find currently, making it much harder to debug. With a named namespace, the derived type information is found and so the debugger can show the member fields of a derived type (vtable -> type mapping). One can manually do all of this with enough effort, and maybe eventually the debuggers will support it directly, but at this time I see simply naming the namespace as the easiest answer.
|
||
namespace AppInstaller::CLI | ||
{ | ||
struct ConfigureExportCommand final : public Command |
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.
My 2🪙: This isn't large enough to warrant a new file, which is to say that if a subcommand were itself rather complex I think it would be ok to break it out (or if it had its own subcommands, etc.)
|
||
ValueSet settings; | ||
settings.Insert(s_Setting_Id, PropertyValue::CreateString(packageIdWide)); | ||
settings.Insert(s_Setting_Source, PropertyValue::CreateString(s_WinGetSource)); |
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.
I feel like you either have to require the source to be provided or you need to search for it so you can know the source.
If you searched for it, you could also set the description to Install <NAME>
rather than the identifier again.
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.
I don't disagree, but that's a feature request or at least another PR.
src/Microsoft.Management.Configuration.Processor/Extensions/HashtableExtensions.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.Management.Configuration.Processor/Extensions/HashtableExtensions.cs
Outdated
Show resolved
Hide resolved
@@ -162,7 +162,11 @@ namespace AppInstaller::CLI::Execution | |||
Max | |||
}; | |||
|
|||
bool Contains(Type arg) const { return (m_parsedArgs.count(arg) != 0); } | |||
template<typename... T, std::enable_if_t<(... && std::is_same_v<T, Args::Type>), bool> = true> |
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.
Pretty sure you can just do:
template<typename... T, std::enable_if_t<(... && std::is_same_v<T, Args::Type>), bool> = true> | |
template<Args::Type... T> |
@@ -162,7 +162,11 @@ namespace AppInstaller::CLI::Execution | |||
Max | |||
}; | |||
|
|||
bool Contains(Type arg) const { return (m_parsedArgs.count(arg) != 0); } | |||
template<typename... T, std::enable_if_t<(... && std::is_same_v<T, Args::Type>), bool> = true> | |||
bool Contains(T... arg) const |
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.
You could also use a std::initializer_list
with the low cost of putting {}
around your parameter list. But it definitely wouldn't be as fun as figuring out this.
This PR introduces the
configure export
command as an exprimental feature. This is mostly a proof of concept and should not be considered a full feature.Scenario A - Create a configuration to install a winget package.
Use
--pacakgeId
with the package identifier of an application in the winget source to produce a configuration file that uses theMicrosoft.WinGet.DSC/WinGetPackage
resource to install the package via winget. Right now, we don't validate if the package id exists and will just copy what the user sets into the settings of the resource.Scenario B - 'Export' the configuration from the specified resource.
Use both
--module
and--resource
to get the configuration of a resource and add it to the configuration file. Internally, configuration will install the module (if not installed already) and call Get on the resource. We will then try to serialize its property into the configuration file. Current limitation is that if a resource has a required setting (like WinGetPackage required Id) it won't work. If the resource is not found in the gallery a retry will be performed allowing prereleased modules in the case it exists.Scenario C - Mix of A and B
If
--packageId
,--module
and--resource
are used, configure export will produce two resources. The first one is theWinGetPackage
for the specified package. The second one is the same as in B, with the difference that it includes a dependency of the previously createdWinGetPackage
resource.Scenario D - Configuration file already exists.
If the file passed to the
--output
parameters already exists and is a valid configuration file, the resources will be appended. There is currently not validation into the correctness of this, so it can result in a configuration with resources with the same id.For example
winget configure export --packageId Microsoft.AppInstaller --module Microsoft.WinGet.DSC --resource WinGetUserSettings -o test_export.yml
would produce the following fileMicrosoft Reviewers: Open in CodeFlow