diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/CommonUtils.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/CommonUtils.cs
index e51685365..97fdbc978 100644
--- a/src/Microsoft.PowerShell.Commands.Diagnostics/CommonUtils.cs
+++ b/src/Microsoft.PowerShell.Commands.Diagnostics/CommonUtils.cs
@@ -11,6 +11,7 @@ namespace Microsoft.PowerShell.Commands.Diagnostics.Common
internal static class CommonUtilities
{
+#if !CORECLR
//
// StringArrayToString helper converts a string array into a comma-separated string.
// Note this has only limited use, individual strings cannot have commas.
@@ -111,13 +112,13 @@ namespace Microsoft.PowerShell.Commands.Diagnostics.Common
}
return formatError;
}
+#endif
public static ResourceManager GetResourceManager()
{
// this naming pattern is dictated by the dotnet cli
return new ResourceManager("Microsoft.PowerShell.Commands.Diagnostics.resources.GetEventResources", typeof(CommonUtilities).GetTypeInfo().Assembly);
}
-
}
}
diff --git a/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs b/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs
index 5f48ed3bc..073951c3c 100644
--- a/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs
+++ b/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs
@@ -175,7 +175,7 @@ namespace System.Management.Automation
///
/// Singleton instance of PowerShellAssemblyLoadContext
///
- public static PowerShellAssemblyLoadContext Instance
+ internal static PowerShellAssemblyLoadContext Instance
{
get; private set;
}
@@ -376,7 +376,19 @@ namespace System.Management.Automation
string tpaStrongName;
if (coreClrTypeCatalog.TryGetValue(namespaceQualifiedTypeName, out tpaStrongName))
{
- return new Assembly[] { GetTrustedPlatformAssembly(tpaStrongName) };
+ try
+ {
+ return new Assembly[] { GetTrustedPlatformAssembly(tpaStrongName) };
+ }
+ catch (FileNotFoundException)
+ {
+ // It's possible that the type catalog generated in OPS contains more entries than
+ // the one generated in windows build. This is because in OPS we have more freedom
+ // to control what packages to depend on, such as Json.NET.
+ // If we deploy the PSALC.dll generated from OPS to NanoServer, then it's possible
+ // that 'GetTrustedPlatformAssembly(tpaStrongName)' may fail for such entries. In
+ // this case, we ignore the exception and return our cached assemblies.
+ }
}
}
@@ -459,6 +471,15 @@ namespace System.Management.Automation
///
/// Set the profile optimization root on the appropriate load context
///
+ ///
+ /// When using PS ALC as a full fledged ALC in OPS, we don't enable profile optimization.
+ /// This is because PS assemblies will be recorded in the profile, and the next time OPS
+ /// starts up, the default context will load the PS assemblies pretty early to ngen them
+ /// in another CPU core, so our Load override won't track the loading of them, and thus
+ /// OPS will fail to work.
+ /// The root cause is that dotnet.exe put all PS assemblies in TPA list. If PS assemblies
+ /// are not in TPA list, then we can enable profile optimization without a problem.
+ ///
internal void SetProfileOptimizationRootImpl(string directoryPath)
{
if (this.useResolvingHandlerOnly)
@@ -468,6 +489,15 @@ namespace System.Management.Automation
///
/// Start the profile optimization on the appropriate load context
///
+ ///
+ /// When using PS ALC as a full fledged ALC in OPS, we don't enable profile optimization.
+ /// This is because PS assemblies will be recorded in the profile, and the next time OPS
+ /// starts up, the default context will load the PS assemblies pretty early to ngen them
+ /// in another CPU core, so our Load override won't track the loading of them, and thus
+ /// OPS will fail to work.
+ /// The root cause is that dotnet.exe put all PS assemblies in TPA list. If PS assemblies
+ /// are not in TPA list, then we can enable profile optimization without a problem.
+ ///
internal void StartProfileOptimizationImpl(string profile)
{
if (this.useResolvingHandlerOnly)
@@ -620,38 +650,15 @@ namespace System.Management.Automation
///
private Assembly GetTrustedPlatformAssembly(string tpaStrongName)
{
- Assembly asmLoaded;
+ // We always depend on the default context to load the TPAs that are recorded in
+ // the type catalog.
+ // - If the requested TPA is already loaded, then 'Assembly.Load' will just get
+ // it back from the cache of default context.
+ // - If the requested TPA is not loaded yet, then 'Assembly.Load' will make the
+ // default context to load it
AssemblyName assemblyName = new AssemblyName(tpaStrongName);
-
- // With the current standalone-app model of OPS, .NET Core libraries and PS assemblies are mixed together in one folder.
- // So when using PSALC as a full fledged ALC in OPS, some TPAs might be loaded by our Load override. In that case, if we
- // alwasy call Assembly.Load here to get a TPA, we might end up with a different Assembly instance of the the same TPA
- // loaded in the default load context. We want to use the same assembly instance for type resolution in PS to avoid creating
- // types and running .NET code from different assembly instances of the same DLL. Therefore, we try our cache first to see
- // if the requested TPA is already loaded. If so, we use that one. If not, we load it in default context using Assembly.Load.
- // Once a TPA is loaded in the default context, the same Assembly instance will always be used by custom ALC's when they attempt
- // to resolve an "Assembly.Load" request for the same TPA.
- //
- // For in-box PS of NanoServer/IoT and the share-framework host model of OPS, we don't have the mixed libraries/assemblies
- // problem, and TPAs are always resolved/loaded by the default context. In those cases, checking our cache would be unnecessary,
- // but it won't cause any problems.
-
- // Probe the assembly cache
- if (TryGetAssemblyFromCache(assemblyName, out asmLoaded))
- return asmLoaded;
-
- // Prepare to load the assembly
- lock (syncObj)
- {
- // Probe the cache again in case it's already loaded
- if (TryGetAssemblyFromCache(assemblyName, out asmLoaded))
- return asmLoaded;
-
- // The requested TPA is not loaded by PS ALC, so load it in the default load context using Assembly.Load.
- // There is no need to add it to our cache. It's cached in the default context.
- asmLoaded = Assembly.Load(assemblyName);
- return asmLoaded;
- }
+ Assembly asmLoaded = Assembly.Load(assemblyName);
+ return asmLoaded;
}
///
diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
index 4200b1055..8c3eb882b 100644
--- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
+++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
@@ -5907,21 +5907,32 @@ namespace System.Management.Automation
/// The namespace
private static void HandleNamespace(Dictionary entryCache, string @namespace)
{
- if (!string.IsNullOrEmpty(@namespace))
+ if (string.IsNullOrEmpty(@namespace))
{
+ return;
+ }
+
+ int dotIndex = 0;
+ while (dotIndex != -1)
+ {
+ dotIndex = @namespace.IndexOf('.', dotIndex + 1);
+ string subNamespace = dotIndex != -1
+ ? @namespace.Substring(0, dotIndex)
+ : @namespace;
+
TypeCompletionMapping entry;
- if (!entryCache.TryGetValue(@namespace, out entry))
+ if (!entryCache.TryGetValue(subNamespace, out entry))
{
entry = new TypeCompletionMapping
{
- Key = @namespace,
- Completions = { new NamespaceCompletion { Namespace = @namespace } }
+ Key = subNamespace,
+ Completions = { new NamespaceCompletion { Namespace = subNamespace } }
};
- entryCache.Add(@namespace, entry);
+ entryCache.Add(subNamespace, entry);
}
else if (!entry.Completions.OfType().Any())
{
- entry.Completions.Add(new NamespaceCompletion { Namespace = @namespace });
+ entry.Completions.Add(new NamespaceCompletion { Namespace = subNamespace });
}
}
}
diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs
index f60a5ff75..5bf3efbac 100644
--- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs
+++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs
@@ -1818,7 +1818,7 @@ namespace Microsoft.PowerShell.Commands
DirectoryInfo parent = null;
try
{
- parent = ClrFacade.GetParent(moduleManifestPath);
+ parent = Directory.GetParent(moduleManifestPath);
}
catch (IOException)
{
diff --git a/src/System.Management.Automation/engine/Modules/TestModuleManifestCommand.cs b/src/System.Management.Automation/engine/Modules/TestModuleManifestCommand.cs
index b74c18bfa..f3ade9228 100644
--- a/src/System.Management.Automation/engine/Modules/TestModuleManifestCommand.cs
+++ b/src/System.Management.Automation/engine/Modules/TestModuleManifestCommand.cs
@@ -241,7 +241,7 @@ namespace Microsoft.PowerShell.Commands
DirectoryInfo parent = null;
try
{
- parent = ClrFacade.GetParent(filePath);
+ parent = Directory.GetParent(filePath);
}
catch (IOException) { }
catch (UnauthorizedAccessException) { }
diff --git a/src/System.Management.Automation/resources/ParserStrings.resx b/src/System.Management.Automation/resources/ParserStrings.resx
index 695cdc596..45c808cb5 100644
--- a/src/System.Management.Automation/resources/ParserStrings.resx
+++ b/src/System.Management.Automation/resources/ParserStrings.resx
@@ -1351,8 +1351,8 @@ ModuleVersion : Version of module to import. If used, ModuleName must represent
Cannot run a document in PowerShell Core: {0}.
-
- The default AssemblyLoadContext in use is invalid. The default AssemblyLoadContext for PowerShell Core should be of type 'PowerShellAssemblyLoader'.
+
+ 'PowerShellAssemblyLoadContext' is not initialized.
Multiple type constraints are not allowed on a method parameter.
diff --git a/src/System.Management.Automation/utils/ClrFacade.cs b/src/System.Management.Automation/utils/ClrFacade.cs
index 16d085820..f9cd78eb4 100644
--- a/src/System.Management.Automation/utils/ClrFacade.cs
+++ b/src/System.Management.Automation/utils/ClrFacade.cs
@@ -344,6 +344,10 @@ namespace System.Management.Automation
{
get
{
+ if (PowerShellAssemblyLoadContext.Instance == null)
+ {
+ throw new InvalidOperationException(ParserStrings.LoadContextNotInitialized);
+ }
return PowerShellAssemblyLoadContext.Instance;
}
}
@@ -512,15 +516,6 @@ namespace System.Management.Automation
#endif
}
- ///
- /// Facade for Directory.GetParent(string)
- ///
- internal static DirectoryInfo GetParent(string path)
- {
- // Porting note: this is in recent CoreCLR
- return Directory.GetParent(path);
- }
-
///
/// Facade for ManagementDateTimeConverter.ToDmtfDateTime(DateTime)
///
diff --git a/src/powershell-native/nativemsh/pwrshcommon/pwrshcommon.cpp b/src/powershell-native/nativemsh/pwrshcommon/pwrshcommon.cpp
index 0f9deb37e..64d0a014d 100644
--- a/src/powershell-native/nativemsh/pwrshcommon/pwrshcommon.cpp
+++ b/src/powershell-native/nativemsh/pwrshcommon/pwrshcommon.cpp
@@ -1454,14 +1454,14 @@ namespace NativeMsh
props[nProps] = L"TRUSTED_PLATFORM_ASSEMBLIES";
std::wstring tempStr = assemblyList.str();
vals[nProps] = tempStr.c_str();
- nProps++;
+ nProps++;
props[nProps] = L"APP_PATHS";
- vals[nProps] = hostEnvironment.GetHostDirectoryPath();
+ vals[nProps] = L"";
nProps++;
props[nProps] = L"APP_NI_PATHS";
- vals[nProps] = hostEnvironment.GetHostDirectoryPath();
+ vals[nProps] = L"";
nProps++;
// Create the customized AppDomainManager out of the SandboxHelper class
diff --git a/test/powershell/Host/TabCompletion/BugFix.Tests.ps1 b/test/powershell/Host/TabCompletion/BugFix.Tests.ps1
new file mode 100644
index 000000000..18a64f782
--- /dev/null
+++ b/test/powershell/Host/TabCompletion/BugFix.Tests.ps1
@@ -0,0 +1,9 @@
+Describe "Issue#682 - [system.manage] should work" {
+
+ It "[system.manage" {
+ $result = TabExpansion2 -inputScript "[system.manage" -cursorColumn "[system.manage".Length
+ $result | Should Not BeNullOrEmpty
+ $result.CompletionMatches.Count | Should Be 1
+ $result.CompletionMatches[0].CompletionText | Should Be "System.Management"
+ }
+}