Skip to content
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 support for --Installer-Type argument for commands #3516

Merged
merged 12 commits into from Aug 30, 2023

Conversation

ryfu-msft
Copy link
Contributor

@ryfu-msft ryfu-msft commented Aug 10, 2023

Resolves #1166

Changes:

  • Adds the --installer-type argument to the Install, Upgrade, and Show command.
  • Modifies settings schema to allow for installer type preferences and requirements.
  • Added the corresponding argument to the COM InstallOptions.
  • Updated the manifest installer comparator to handle both installer type preferences and requirements.

Tests:

  • Unit tests to verify the manifest comparator when providing the installerType arg, preference, and requirements.
  • E2E tests to verify the behavior for COM install, Install, and Show.
Microsoft Reviewers: codeflow:open?pullrequest=https://github.com/microsoft/winget-cli/pull/3516&drop=dogfoodAlpha

@ryfu-msft ryfu-msft requested a review from a team as a code owner August 10, 2023 18:51
@microsoft-github-policy-service microsoft-github-policy-service bot added Issue-Feature This is a feature request for the Windows Package Manager client. Area-Settings Issue related to WinGet Settings labels Aug 10, 2023
@ryfu-msft ryfu-msft requested a review from Trenly August 11, 2023 17:10

bool ContainsInstallerType(const std::vector<InstallerTypeEnum>& selection, InstallerTypeEnum installerType)
{
return std::find(selection.begin(), selection.end(), installerType) != selection.end();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, thinking more about this, I wonder if it would make sense to have a templated utility function for checking if an object is contained within a container.

Although, considering that this PR is required for 1.6, it might make sense not to create a utility function.


I'm thinking something like this might work, but I'm not certain

template <template<typename, typename> typename Container, typename Allocator, typename Value>
bool ContainsObject(Container<Value, Allocator> container, Value value) {
  return std::find(container.begin(), container.end(), value) != container.end();
}

"portable"
],
"minItems": 1,
"maxItems": 9
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I don't see much point in having maxItems set to n-1.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the other settings arrays declare a maxItems so I followed it just to be consistent.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's weird but ok, Anyway this settings schema is not used in code for enforcement, it's just informational only for now.

Comment on lines +104 to +111
"inno",
"wix",
"msi",
"nullsoft",
"zip",
"msix",
"exe",
"burn",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would a user really care about whether something is an msi or an msi made with some-tool?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this essentially mean that we would need an "InstallerTechnologyType" for each Installer? Effectively reducing it to portable, exe, msi, msix, and msstore?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's what I'm suggesting. But I don't know if it would be a good idea. I don't think most people would care about the difference between a wix and an msi installer, but for people who do care I think it would be confusing if the set of types here is different than in the manifest.

@@ -140,6 +140,18 @@ The `architectures` behavior affects what architectures will be selected when in
},
```

### Installer Types

The `installerTypes` behavior affects what installer types will be selected when installing a package. The matching parameter is `--installer-type`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this work for scenarios like "zip containing exe" or "exe that installs an msi"?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zip uses the EffectiveInstallerType, but that brings up a good point - if someone has {zip, exe} as their preferences, because the check is against both base and effective type, a zip->msi could still be chosen even if a zip->exe exists

And another great point about the exe that installs an msi or msix; AppsAndFeaturesEntries->InstallerType might need to be considered

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For zip containing exe, I check both the baseInstallerType (for zip) and effective installer type to determine if an installer satisfies the preference/requirement so I believe that scenario is covered. I didn't do anything different for "exe that installs an msi" as I only consider what is shown in the manifest

"wix",
"msi",
"nullsoft",
"zip",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is zip an installer type users would care about?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it will be a common scenario, but it should still be supported if people prefer that installer type.

src/AppInstallerCLICore/Workflows/ManifestComparator.cpp Outdated Show resolved Hide resolved
Manifest::InstallerTypeEnum installerType = Manifest::ConvertToInstallerTypeEnum(i);
if (installerType == Manifest::InstallerTypeEnum::Unknown)
{
return {};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to just skip the ones that are not valid instead of dropping everything? That way, if in future versions we add new installer types, people could use those same settings files on this version.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I basically followed how we validate the other settings (like Architecture preference that drop if there is an invalid value) so I left it as is because I don't think installer type should behave any differently.

@@ -196,5 +202,24 @@ public static void InitializeAllFeatures(bool status)
ConfigureFeature("windowsFeature", status);
ConfigureFeature("download", status);
}

private static JObject GetJsonSettingsObject(string objectName, string propertyName)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this function do?
It seems like it parses the settings file, then adds an object with a single empty property?
That is weird to me, and the method name doesn't help.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about something like

private static JObject GetJsonSettingsObjectAndCreateEmptyProperty(string[] propertyPath...)
{
    JObject settingsJson = JObject.Parse(File.ReadAllText(TestSetup.Parameters.SettingsJsonFilePath));
    var currentNode = settings.Json;
    foreach (var key in propertyPath)
    {
        if (!currentNode.ContainsKey(key))
        {
            currentNode[key] = new JObject();
        }
        currentNode = currentNode[key];
    }

    return settingsJson;
}

(Not sure if this even compiles...)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the helper method to be a little more generic so that it only returns the json settings object that you specify and doesn't do anything with creating a single empty property (which I also agree is kind of weird).

yao-msft
yao-msft previously approved these changes Aug 26, 2023
"portable"
],
"minItems": 1,
"maxItems": 9
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's weird but ok, Anyway this settings schema is not used in code for enforcement, it's just informational only for now.

}

bool ContainsInstallerType(const std::vector<InstallerTypeEnum>& selection, InstallerTypeEnum installerType)
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: move to private

ContainsInstallerType(m_preference, second.EffectiveInstallerType()) ||
ContainsInstallerType(m_preference, second.BaseInstallerType);

if (isFirstInstallerTypePreferred == isSecondInstallerTypePreferred)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit torn about whether making the preference ordered vs unordered. Making it unordered will limit the user's ability to prefer a specific installer type over another and all other preferences are ordered. Making it ordered seems too strong for installer type though. maybe a middle ground will be making it ordered and put this comparator in the last on line 765 so it's not that significant in the end (btw, putting the comparator to last should be done regardless of whether we decide it ordered or unordered)

@ryfu-msft ryfu-msft merged commit 020c2f0 into microsoft:master Aug 30, 2023
8 checks passed
@ryfu-msft ryfu-msft deleted the installerTypeArg branch August 30, 2023 20:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Settings Issue related to WinGet Settings Issue-Feature This is a feature request for the Windows Package Manager client.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Specify InstallerType
4 participants