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 default module root setting for configuration #4974

Merged
merged 12 commits into from
Nov 26, 2024
Merged
15 changes: 15 additions & 0 deletions doc/Settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,21 @@ The `purgePortablePackage` behavior affects the default behavior for uninstallin
},
```

## Configure Behavior

The `configureBehavior` settings affect the default behavior of applying a configuration.

### Default Module Root
The `defaultModuleRoot` behavior affects the default root directory where modules are installed to. Defaults to `%LOCALAPPDATA%/Microsoft/WinGet/Configuration/Modules` if value is not set or is invalid.

> Note: This setting value must be an absolute path.

```json
"configureBehavior": {
"defaultModuleRoot": "C:/Program Files/Modules/"
},
```

## Telemetry

The `telemetry` settings control whether winget writes ETW events that may be sent to Microsoft on a default installation of Windows.
Expand Down
11 changes: 11 additions & 0 deletions schemas/JSON/settings/settings.schema.0.2.json
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,17 @@
}
}
},
"ConfigureBehavior": {
"description": "Configure settings",
"type": "object",
"properties": {
"defaultModuleRoot": {
"description": "The default root directory where PowerShell modules are installed to when applying a configuration.",
"type": "string",
"maxLength": 32767
}
}
},
"DownloadBehavior": {
"description": "Download settings",
"type": "object",
Expand Down
11 changes: 9 additions & 2 deletions src/AppInstallerCLICore/ConfigurationCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace AppInstaller::CLI
struct ModulePathInfo
{
SetProcessorFactory::PwshConfigurationProcessorLocation location;
std::optional<std::string_view> customLocation;
std::optional<std::string> customLocation;
};

ModulePathInfo GetModulePathInfo(Execution::Args& execArgs)
Expand All @@ -44,10 +44,17 @@ namespace AppInstaller::CLI
}
else
{
return { SetProcessorFactory::PwshConfigurationProcessorLocation::Custom, execArgs.GetArg(Execution::Args::Type::ConfigurationModulePath) };
return { SetProcessorFactory::PwshConfigurationProcessorLocation::Custom, std::string(execArgs.GetArg(Execution::Args::Type::ConfigurationModulePath)) };
}
}

std::filesystem::path defaultModuleRoot = Settings::User().Get<Settings::Setting::ConfigureDefaultModuleRoot>();

if (!defaultModuleRoot.empty())
{
return { SetProcessorFactory::PwshConfigurationProcessorLocation::Custom, defaultModuleRoot.u8string() };
}

return { SetProcessorFactory::PwshConfigurationProcessorLocation::WinGetModulePath, {} };
}
}
Expand Down
24 changes: 24 additions & 0 deletions src/AppInstallerCLIE2ETests/ConfigureCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,30 @@ public void ConfigureFromTestRepo()
Constants.SimpleTestModuleName)));
}

/// <summary>
/// Simple test to confirm that the module was installed to the location specified in the DefaultModuleRoot settings.
/// </summary>
[Test]
public void ConfigureFromTestRepo_DefaultModuleRootSetting()
{
TestCommon.EnsureModuleState(Constants.SimpleTestModuleName, present: false);
string moduleTestDir = TestCommon.GetRandomTestDir();
WinGetSettingsHelper.ConfigureConfigureBehavior(Constants.DefaultModuleRoot, moduleTestDir);

string args = TestCommon.GetTestDataFile("Configuration\\Configure_TestRepo_Location.yml");
var result = TestCommon.RunAICLICommand(CommandAndAgreementsAndVerbose, args);

WinGetSettingsHelper.ConfigureConfigureBehavior(Constants.DefaultModuleRoot, string.Empty);
bool moduleExists = Directory.Exists(Path.Combine(moduleTestDir, Constants.SimpleTestModuleName));
if (moduleExists)
{
Directory.Delete(moduleTestDir, true);
}

Assert.AreEqual(0, result.ExitCode);
Assert.True(moduleExists);
}

/// <summary>
/// Simple test to confirm that the module was installed in the right location.
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions src/AppInstallerCLIE2ETests/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ public class Constants
public const string PortablePackageMachineRoot = "portablePackageMachineRoot";
public const string InstallBehaviorScope = "scope";
public const string InstallerTypes = "installerTypes";
public const string DefaultModuleRoot = "defaultModuleRoot";

// Configuration
public const string PSGalleryName = "PSGallery";
Expand Down
13 changes: 11 additions & 2 deletions src/AppInstallerCLIE2ETests/ErrorCommand.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// <copyright file="ErrorCommand.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
// </copyright>
Expand All @@ -14,6 +14,15 @@ namespace AppInstallerCLIE2ETests
/// </summary>
public class ErrorCommand
{
/// <summary>
/// Reset settings file to avoid affecting output from error command.
/// </summary>
ryfu-msft marked this conversation as resolved.
Show resolved Hide resolved
[OneTimeSetUp]
public void OneTimeSetup()
{
WinGetSettingsHelper.InitializeWingetSettings();
}

/// <summary>
/// Tests 0.
/// </summary>
Expand Down Expand Up @@ -127,4 +136,4 @@ public void String()
Assert.True(result.StdOut.Contains("APPINSTALLER_CLI_ERROR_UNSUPPORTED_RESTSOURCE"));
}
}
}
}
20 changes: 20 additions & 0 deletions src/AppInstallerCLIE2ETests/Helpers/WinGetSettingsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ public static void InitializeWingetSettings()
{
}
},
{
"configureBehavior",
new Hashtable()
{
}
},
};

// Run winget one time to initialize settings directory
Expand Down Expand Up @@ -108,6 +114,20 @@ public static void ConfigureInstallBehavior(string settingName, string value)
SetWingetSettings(settingsJson);
}

/// <summary>
/// Configure the configuration behavior.
/// </summary>
/// <param name="settingName">Setting name.</param>
/// <param name="value">Setting value.</param>
public static void ConfigureConfigureBehavior(string settingName, string value)
{
JObject settingsJson = GetJsonSettingsObject("configureBehavior");
var configureBehavior = settingsJson["configureBehavior"];
configureBehavior[settingName] = value;

SetWingetSettings(settingsJson);
}

/// <summary>
/// Configure the install behavior preferences.
/// </summary>
Expand Down
15 changes: 15 additions & 0 deletions src/AppInstallerCLITests/UserSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,21 @@ TEST_CASE("SettingsDownloadDefaultDirectory", "[settings]")
}
}

TEST_CASE("SettingsConfigureDefaultModuleRoot", "[settings]")
{
auto again = DeleteUserSettingsFiles();

SECTION("Valid path")
{
std::string_view json = R"({ "configureBehavior": { "defaultModuleRoot": "C:/Foo/Bar" } })";
SetSetting(Stream::PrimaryUserSettings, json);
UserSettingsTest userSettingTest;

REQUIRE(userSettingTest.Get<Setting::ConfigureDefaultModuleRoot>() == "C:/Foo/Bar");
REQUIRE(userSettingTest.GetWarnings().size() == 0);
}
}

TEST_CASE("SettingsArchiveExtractionMethod", "[settings]")
{
auto again = DeleteUserSettingsFiles();
Expand Down
4 changes: 4 additions & 0 deletions src/AppInstallerCommonCore/Public/winget/UserSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ namespace AppInstaller::Settings
UninstallPurgePortablePackage,
// Download behavior
DownloadDefaultDirectory,
// Configure behavior
ConfigureDefaultModuleRoot,
// Interactivity
InteractivityDisable,
#ifndef AICLI_DISABLE_TEST_HOOKS
Expand Down Expand Up @@ -185,6 +187,8 @@ namespace AppInstaller::Settings
SETTINGMAPPING_SPECIALIZATION(Setting::UninstallPurgePortablePackage, bool, bool, false, ".uninstallBehavior.purgePortablePackage"sv);
// Download behavior
SETTINGMAPPING_SPECIALIZATION(Setting::DownloadDefaultDirectory, std::string, std::filesystem::path, {}, ".downloadBehavior.defaultDownloadDirectory"sv);
// Configure behavior
SETTINGMAPPING_SPECIALIZATION(Setting::ConfigureDefaultModuleRoot, std::string, std::filesystem::path, {}, ".configureBehavior.defaultModuleRoot"sv);

// Network
SETTINGMAPPING_SPECIALIZATION(Setting::NetworkDownloader, std::string, InstallerDownloader, InstallerDownloader::Default, ".network.downloader"sv);
Expand Down
5 changes: 5 additions & 0 deletions src/AppInstallerCommonCore/UserSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,11 @@ namespace AppInstaller::Settings
return ValidatePathValue(value);
}

WINGET_VALIDATE_SIGNATURE(ConfigureDefaultModuleRoot)
{
return ValidatePathValue(value);
}

WINGET_VALIDATE_SIGNATURE(NetworkDownloader)
{
static constexpr std::string_view s_downloader_default = "default";
Expand Down
Loading