Merge pull request #1060 from PowerShell/xdg
XDG Changes I like these tests much better now - far easier to follow
This commit is contained in:
commit
eeb715bf4e
8 changed files with 270 additions and 35 deletions
|
@ -185,15 +185,17 @@ namespace Microsoft.PowerShell
|
||||||
{
|
{
|
||||||
profileDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) +
|
profileDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) +
|
||||||
@"\Microsoft\Windows\PowerShell";
|
@"\Microsoft\Windows\PowerShell";
|
||||||
} else
|
|
||||||
{
|
|
||||||
profileDir = System.IO.Path.Combine(Environment.GetEnvironmentVariable("HOME"), ".powershell");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Directory.Exists(profileDir))
|
if (!Directory.Exists(profileDir))
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(profileDir);
|
Directory.CreateDirectory(profileDir);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
profileDir = Platform.SelectProductNameForDirectory(Platform.XDG_Type.CACHE);
|
||||||
|
}
|
||||||
|
|
||||||
ClrFacade.SetProfileOptimizationRoot(profileDir);
|
ClrFacade.SetProfileOptimizationRoot(profileDir);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
@ -268,7 +270,6 @@ namespace Microsoft.PowerShell
|
||||||
: "StartupProfileData-NonInteractive");
|
: "StartupProfileData-NonInteractive");
|
||||||
exitCode = theConsoleHost.Run(cpp, !string.IsNullOrEmpty(preStartWarning));
|
exitCode = theConsoleHost.Run(cpp, !string.IsNullOrEmpty(preStartWarning));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
|
@ -169,24 +169,39 @@ namespace Microsoft.PowerShell
|
||||||
WordDelimiters = DefaultWordDelimiters;
|
WordDelimiters = DefaultWordDelimiters;
|
||||||
HistorySearchCaseSensitive = DefaultHistorySearchCaseSensitive;
|
HistorySearchCaseSensitive = DefaultHistorySearchCaseSensitive;
|
||||||
HistorySaveStyle = DefaultHistorySaveStyle;
|
HistorySaveStyle = DefaultHistorySaveStyle;
|
||||||
|
|
||||||
|
string historyFileName = hostName + "_history.txt";
|
||||||
#if CORECLR
|
#if CORECLR
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // MS Windows
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // MS Windows
|
||||||
{
|
{
|
||||||
HistorySavePath = System.IO.Path.Combine(Environment.ExpandEnvironmentVariables("%AppData%"),
|
HistorySavePath = System.IO.Path.Combine(Environment.GetEnvironmentVariable("APPDATA"),
|
||||||
@"\Microsoft\Windows\PowerShell\PSReadline\",
|
@"Microsoft\Windows\PowerShell\PSReadline\",
|
||||||
hostName + "_history.txt");
|
historyFileName);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
HistorySavePath = System.IO.Path.Combine(
|
// PSReadline does not have access to Utils.CorePSPlatform. Must set PSReadline path separately
|
||||||
Environment.GetEnvironmentVariable("HOME"),
|
string historyPath = System.Environment.GetEnvironmentVariable("XDG_DATA_HOME");
|
||||||
".powershell",
|
|
||||||
|
if (!String.IsNullOrEmpty(historyPath))
|
||||||
|
{
|
||||||
|
historyPath = System.IO.Path.Combine(historyPath, "powershell", "PSReadLine", historyFileName);
|
||||||
|
HistorySavePath = historyPath;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// History is data, so it goes into .local/share/powershell folder
|
||||||
|
HistorySavePath = System.IO.Path.Combine(Environment.GetEnvironmentVariable("HOME"),
|
||||||
|
".local",
|
||||||
|
"share",
|
||||||
|
"powershell",
|
||||||
"PSReadLine",
|
"PSReadLine",
|
||||||
hostName + "_history.txt");
|
historyFileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
HistorySavePath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
|
HistorySavePath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
|
||||||
+ @"\Microsoft\Windows\PowerShell\PSReadline\" + hostName + "_history.txt";
|
+ @"\Microsoft\Windows\PowerShell\PSReadline\" + historyFileName;
|
||||||
#endif
|
#endif
|
||||||
CommandValidationHandler = null;
|
CommandValidationHandler = null;
|
||||||
CommandsToValidateScriptBlockArguments = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
CommandsToValidateScriptBlockArguments = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
|
|
@ -44,6 +44,15 @@ namespace System.Management.Automation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//enum for selecting the xdgpaths
|
||||||
|
public enum XDG_Type
|
||||||
|
{
|
||||||
|
PROFILE,
|
||||||
|
MODULES,
|
||||||
|
CACHE,
|
||||||
|
DEFAULT
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IsOSX
|
public static bool IsOSX
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -96,8 +105,94 @@ namespace System.Management.Automation
|
||||||
"WSMan.format.ps1xml"
|
"WSMan.format.ps1xml"
|
||||||
};
|
};
|
||||||
|
|
||||||
// directory location of PowerShell for profile loading
|
// function for choosing directory location of PowerShell for profile loading
|
||||||
public static string ProductNameForDirectory = ".powershell";
|
public static string SelectProductNameForDirectory (Platform.XDG_Type dirpath)
|
||||||
|
{
|
||||||
|
|
||||||
|
//TODO: XDG_DATA_DIRS implementation as per GitHub issue #1060
|
||||||
|
|
||||||
|
string xdgconfighome = System.Environment.GetEnvironmentVariable("XDG_CONFIG_HOME");
|
||||||
|
string xdgdatahome = System.Environment.GetEnvironmentVariable("XDG_DATA_HOME");
|
||||||
|
string xdgcachehome = System.Environment.GetEnvironmentVariable("XDG_CACHE_HOME");
|
||||||
|
string xdgConfigHomeDefault = Path.Combine ( System.Environment.GetEnvironmentVariable("HOME"), ".config", "powershell");
|
||||||
|
string xdgModuleDefault = Path.Combine ( System.Environment.GetEnvironmentVariable("HOME"), ".local", "share", "powershell", "Modules");
|
||||||
|
string xdgCacheDefault = Path.Combine (System.Environment.GetEnvironmentVariable("HOME"), ".cache", "powershell");
|
||||||
|
|
||||||
|
switch (dirpath){
|
||||||
|
case Platform.XDG_Type.PROFILE:
|
||||||
|
//the user has set XDG_CONFIG_HOME corrresponding to profile path
|
||||||
|
if (String.IsNullOrEmpty(xdgconfighome))
|
||||||
|
{
|
||||||
|
//xdg values have not been set
|
||||||
|
return xdgConfigHomeDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Path.Combine(xdgconfighome, "powershell");
|
||||||
|
}
|
||||||
|
|
||||||
|
case Platform.XDG_Type.MODULES:
|
||||||
|
//the user has set XDG_DATA_HOME corresponding to module path
|
||||||
|
if (String.IsNullOrEmpty(xdgdatahome)){
|
||||||
|
|
||||||
|
//xdg values have not been set
|
||||||
|
if (!Directory.Exists(xdgModuleDefault)) //module folder not always guaranteed to exist
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(xdgModuleDefault);
|
||||||
|
}
|
||||||
|
return xdgModuleDefault;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Path.Combine(xdgdatahome, "powershell", "Modules");
|
||||||
|
}
|
||||||
|
|
||||||
|
case Platform.XDG_Type.CACHE:
|
||||||
|
//the user has set XDG_CACHE_HOME
|
||||||
|
if (String.IsNullOrEmpty(xdgcachehome))
|
||||||
|
{
|
||||||
|
//xdg values have not been set
|
||||||
|
if (!Directory.Exists(xdgCacheDefault)) //module folder not always guaranteed to exist
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(xdgCacheDefault);
|
||||||
|
}
|
||||||
|
|
||||||
|
return xdgCacheDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(Path.Combine(xdgcachehome, "powershell")))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(Path.Combine(xdgcachehome, "powershell"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Path.Combine(xdgcachehome, "powershell");
|
||||||
|
}
|
||||||
|
|
||||||
|
case Platform.XDG_Type.DEFAULT:
|
||||||
|
//default for profile location
|
||||||
|
return xdgConfigHomeDefault;
|
||||||
|
|
||||||
|
default:
|
||||||
|
//xdgConfigHomeDefault needs to be created in the edge case that we do not have the folder or it was deleted
|
||||||
|
//This folder is the default in the event of all other failures for data storage
|
||||||
|
if (!Directory.Exists(xdgConfigHomeDefault))
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Directory.CreateDirectory(xdgConfigHomeDefault);
|
||||||
|
}
|
||||||
|
catch{
|
||||||
|
|
||||||
|
Console.Error.WriteLine("Failed to create default data directory: " + xdgConfigHomeDefault);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return xdgConfigHomeDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// ComObjectType is null on CoreCLR for Linux since there is
|
// ComObjectType is null on CoreCLR for Linux since there is
|
||||||
// no COM support on Linux
|
// no COM support on Linux
|
||||||
|
|
|
@ -1015,8 +1015,10 @@ namespace System.Management.Automation
|
||||||
{
|
{
|
||||||
cacheStoreLocation =
|
cacheStoreLocation =
|
||||||
Environment.GetEnvironmentVariable("PSModuleAnalysisCachePath") ??
|
Environment.GetEnvironmentVariable("PSModuleAnalysisCachePath") ??
|
||||||
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
(Platform.IsWindows
|
||||||
@"Microsoft\Windows\PowerShell\ModuleAnalysisCache");
|
? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||||
|
@"Microsoft\Windows\PowerShell\ModuleAnalysisCache")
|
||||||
|
: Path.Combine(Platform.SelectProductNameForDirectory(Platform.XDG_Type.CACHE), "ModuleAnalysisCache"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -547,15 +547,22 @@ namespace System.Management.Automation
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>personal module path</returns>
|
/// <returns>personal module path</returns>
|
||||||
internal static string GetPersonalModulePath()
|
internal static string GetPersonalModulePath()
|
||||||
|
{
|
||||||
|
if (Platform.IsWindows)
|
||||||
{
|
{
|
||||||
string personalModuleRoot = Path.Combine(
|
string personalModuleRoot = Path.Combine(
|
||||||
Path.Combine(
|
Path.Combine(
|
||||||
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
|
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
|
||||||
Utils.ProductNameForDirectory),
|
Utils.ProductNameForDirectory),
|
||||||
Utils.ModuleDirectory);
|
Utils.ModuleDirectory);
|
||||||
|
|
||||||
return personalModuleRoot;
|
return personalModuleRoot;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string personalModuleRoot = Platform.SelectProductNameForDirectory(Platform.XDG_Type.MODULES);
|
||||||
|
return personalModuleRoot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the default system-wide module path.
|
/// Gets the default system-wide module path.
|
||||||
|
|
|
@ -606,7 +606,7 @@ namespace System.Management.Automation
|
||||||
/// Profile uses this to control profile loading.
|
/// Profile uses this to control profile loading.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
internal static string ProductNameForDirectory =
|
internal static string ProductNameForDirectory =
|
||||||
Platform.IsWindows ? "WindowsPowerShell" : Platform.ProductNameForDirectory;
|
Platform.IsWindows ? "WindowsPowerShell" : Platform.SelectProductNameForDirectory(Platform.XDG_Type.PROFILE);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The name of the subdirectory that contains packages.
|
/// The name of the subdirectory that contains packages.
|
||||||
|
|
|
@ -198,7 +198,6 @@ namespace System.Management.Automation
|
||||||
|
|
||||||
string profileName = useTestProfile ? "profile_test.ps1" : "profile.ps1";
|
string profileName = useTestProfile ? "profile_test.ps1" : "profile.ps1";
|
||||||
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(shellId))
|
if (!string.IsNullOrEmpty(shellId))
|
||||||
{
|
{
|
||||||
profileName = shellId + "_" + profileName;
|
profileName = shellId + "_" + profileName;
|
||||||
|
|
116
test/powershell/Base-Directory.Tests.ps1
Normal file
116
test/powershell/Base-Directory.Tests.ps1
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
Describe "Configuration file locations" {
|
||||||
|
|
||||||
|
BeforeAll {
|
||||||
|
$powershell = Join-Path -Path $PsHome -ChildPath "powershell"
|
||||||
|
$profileName = "Microsoft.PowerShell_profile.ps1"
|
||||||
|
}
|
||||||
|
|
||||||
|
Context "Default configuration file locations" {
|
||||||
|
|
||||||
|
BeforeAll {
|
||||||
|
|
||||||
|
if ($IsWindows) {
|
||||||
|
$expectedCache = [IO.Path]::Combine($env:LOCALAPPDATA, "Microsoft", "Windows", "PowerShell", "StartupProfileData-NonInteractive")
|
||||||
|
$expectedModule = [IO.Path]::Combine($env:USERPROFILE, "Documents", "WindowsPowerShell", "Modules")
|
||||||
|
$expectedProfile = [io.path]::Combine($env:USERPROFILE, "Documents","WindowsPowerShell",$profileName)
|
||||||
|
$expectedReadline = [IO.Path]::Combine($env:AppData, "Microsoft", "Windows", "PowerShell", "PSReadline", "ConsoleHost_history.txt")
|
||||||
|
} else {
|
||||||
|
$expectedCache = [IO.Path]::Combine($env:HOME, ".cache", "powershell", "StartupProfileData-NonInteractive")
|
||||||
|
$expectedModule = [IO.Path]::Combine($env:HOME, ".local", "share", "powershell", "Modules")
|
||||||
|
$expectedProfile = [io.path]::Combine($env:HOME,".config","powershell",$profileName)
|
||||||
|
$expectedReadline = [IO.Path]::Combine($env:HOME, ".local", "share", "powershell", "PSReadLine", "ConsoleHost_history.txt")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($env:TRAVIS_OS_NAME -eq "osx") {
|
||||||
|
$ItArgs = @{ pending = $true }
|
||||||
|
} else {
|
||||||
|
$ItArgs = @{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BeforeEach {
|
||||||
|
$original_PSMODULEPATH = $env:PSMODULEPATH
|
||||||
|
}
|
||||||
|
|
||||||
|
AfterEach {
|
||||||
|
$env:PSMODULEPATH = $original_PSMODULEPATH
|
||||||
|
}
|
||||||
|
|
||||||
|
It @ItArgs "Profile location should be correct" {
|
||||||
|
& $powershell -noprofile `$PROFILE | Should Be $expectedProfile
|
||||||
|
}
|
||||||
|
|
||||||
|
It @ItArgs "PSMODULEPATH should contain the correct path" {
|
||||||
|
$env:PSMODULEPATH = ""
|
||||||
|
$actual = & $powershell -noprofile `$env:PSMODULEPATH
|
||||||
|
$actual | Should Match ([regex]::Escape($expectedModule))
|
||||||
|
}
|
||||||
|
|
||||||
|
It @ItArgs "PSReadLine history save location should be correct" {
|
||||||
|
& $powershell -noprofile { (Get-PSReadlineOption).HistorySavePath } | Should Be $expectedReadline
|
||||||
|
}
|
||||||
|
|
||||||
|
It @ItArgs "JIT cache should be created correctly" {
|
||||||
|
Remove-Item -ErrorAction SilentlyContinue $expectedCache
|
||||||
|
& $powershell -noprofile { exit }
|
||||||
|
$expectedCache | Should Exist
|
||||||
|
}
|
||||||
|
|
||||||
|
# The ModuleAnalysisCache cannot be forced to exist, thus we cannot test it
|
||||||
|
}
|
||||||
|
|
||||||
|
Context "XDG Base Directory Specification is supported on Linux" {
|
||||||
|
BeforeAll {
|
||||||
|
# Using It @ItArgs, we automatically skip on Windows for all these tests
|
||||||
|
if ($IsWindows) {
|
||||||
|
$ItArgs = @{ skip = $true }
|
||||||
|
} elseif ($env:TRAVIS_OS_NAME -eq "osx") {
|
||||||
|
$ItArgs = @{ pending = $true }
|
||||||
|
} else {
|
||||||
|
$ItArgs = @{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BeforeEach {
|
||||||
|
$original_PSMODULEPATH = $env:PSMODULEPATH
|
||||||
|
$original_XDG_CONFIG_HOME = $env:XDG_CONFIG_HOME
|
||||||
|
$original_XDG_CACHE_HOME = $env:XDG_CACHE_HOME
|
||||||
|
$original_XDG_DATA_HOME = $env:XDG_DATA_HOME
|
||||||
|
}
|
||||||
|
|
||||||
|
AfterEach {
|
||||||
|
$env:PSMODULEPATH = $original_PSMODULEPATH
|
||||||
|
$env:XDG_CONFIG_HOME = $original_XDG_CONFIG_HOME
|
||||||
|
$env:XDG_CACHE_HOME = $original_XDG_CACHE_HOME
|
||||||
|
$env:XDG_DATA_HOME = $original_XDG_DATA_HOME
|
||||||
|
}
|
||||||
|
|
||||||
|
It @ItArgs "Profile should respect XDG_CONFIG_HOME" {
|
||||||
|
$env:XDG_CONFIG_HOME = $TestDrive
|
||||||
|
$expected = [IO.Path]::Combine($TestDrive, "powershell", $profileName)
|
||||||
|
& $powershell -noprofile `$PROFILE | Should Be $expected
|
||||||
|
}
|
||||||
|
|
||||||
|
It @ItArgs "PSMODULEPATH should respect XDG_DATA_HOME" {
|
||||||
|
$env:PSMODULEPATH = ""
|
||||||
|
$env:XDG_DATA_HOME = $TestDrive
|
||||||
|
$expected = [IO.Path]::Combine($TestDrive, "powershell", "Modules")
|
||||||
|
$actual = & $powershell -noprofile `$env:PSMODULEPATH
|
||||||
|
$actual | Should Match $expected
|
||||||
|
}
|
||||||
|
|
||||||
|
It @ItArgs "PSReadLine history should respect XDG_DATA_HOME" {
|
||||||
|
$env:XDG_DATA_HOME = $TestDrive
|
||||||
|
$expected = [IO.Path]::Combine($TestDrive, "powershell", "PSReadLine", "ConsoleHost_history.txt")
|
||||||
|
& $powershell -noprofile { (Get-PSReadlineOption).HistorySavePath } | Should Be $expected
|
||||||
|
}
|
||||||
|
|
||||||
|
It @ItArgs "JIT cache should respect XDG_CACHE_HOME" {
|
||||||
|
$env:XDG_CACHE_HOME = $TestDrive
|
||||||
|
$expected = [IO.Path]::Combine($TestDrive, "powershell", "StartupProfileData-NonInteractive")
|
||||||
|
Remove-Item -ErrorAction SilentlyContinue $expected
|
||||||
|
& $powershell -noprofile { exit }
|
||||||
|
$expected | Should Exist
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue