Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1f40247
[feature] Adding a method to check for an instance member on PSObject.
powercode Jan 27, 2019
fa775bd
Addressing Steve's feedback
powercode Jan 30, 2019
8f14671
Fixing code factor issues
powercode Jan 30, 2019
fa3ff7a
Fixing code factor issues.
powercode Jan 30, 2019
7ecc094
Fixing issue with reversed condition for objects with only remoting p…
powercode Jan 30, 2019
f110a8c
Ensure we only check properties of the correct type.
powercode Jan 30, 2019
92e3ea4
PSObjectFlags and WriteStream
powercode Feb 6, 2019
b28ce56
Fixing code factor issues
powercode Feb 7, 2019
9b40624
Addressing review comments: Cleanup of PSObject member names and acce…
powercode Feb 8, 2019
f205055
Addressing Joel's feedback
powercode Feb 8, 2019
f6f3560
Fixing typo in comment
powercode Feb 9, 2019
f07a3ea
Making the PSObjectFlags enum explicitly private.
powercode Feb 11, 2019
a4da06e
Adding whitespace
powercode Feb 11, 2019
4881f11
Remove extra new lines
daxian-dbw Feb 21, 2019
1519087
Addressing Dongbo's feedback.
powercode Feb 25, 2019
1e2a570
Addressing Dongbo's comments.
powercode Mar 9, 2019
2d5c0e2
CodeFactor fixes
powercode Mar 9, 2019
749a362
Rename the new Adapter abstract method to 'GetFirstMemberOrDefault'
daxian-dbw Mar 11, 2019
cc2d003
Merge pull request #1 from daxian-dbw/myformatting
powercode Mar 12, 2019
702f14d
Some more fixes and refactor
daxian-dbw Mar 13, 2019
af563aa
Merge pull request #2 from daxian-dbw/myformatting
powercode Mar 13, 2019
67981d5
Adding back missing namespace
powercode Mar 13, 2019
ed74852
[Feature] Adding tests and fixing bux in handling of XmlAttributes
powercode Mar 17, 2019
c708c3d
Use forward slashes directory separator
daxian-dbw Mar 20, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ private bool HandlePrimitiveKnownTypePSObject(object source, string property, in

bool sourceHandled = false;
PSObject moSource = source as PSObject;
if (moSource != null && !moSource.immediateBaseObjectIsEmpty)
if (moSource != null && !moSource.ImmediateBaseObjectIsEmpty)
{
// Check if baseObject is primitive known type
object baseObject = moSource.ImmediateBaseObject;
Comment thread
powercode marked this conversation as resolved.
Expand All @@ -367,7 +367,7 @@ private bool HandleKnownContainerTypes(object source, string property, int depth
IDictionary dictionary = null;

// If passed in object is PSObject with no baseobject, return false.
if (mshSource != null && mshSource.immediateBaseObjectIsEmpty)
if (mshSource != null && mshSource.ImmediateBaseObjectIsEmpty)
{
return false;
}
Expand Down Expand Up @@ -411,7 +411,7 @@ private bool HandleKnownContainerTypes(object source, string property, int depth
// We serialize properties of enumerable and on deserialization mark the object
// as Deserialized. So if object is marked deserialized, we should write properties.
// Note: we do not serialize the properties of IEnumerable if depth is zero.
if (depth != 0 && (ct == ContainerType.Enumerable || (mshSource != null && mshSource.isDeserialized)))
if (depth != 0 && (ct == ContainerType.Enumerable || (mshSource != null && mshSource.IsDeserialized)))
{
// Note:Depth is the depth for serialization of baseObject.
// Depth for serialization of each property is one less.
Expand Down Expand Up @@ -595,7 +595,7 @@ private void HandleComplexTypePSObject(PSObject source, string property, int dep
bool isEnum = false;
bool isPSObject = false;

if (!source.immediateBaseObjectIsEmpty)
if (!source.ImmediateBaseObjectIsEmpty)
{
isEnum = source.ImmediateBaseObject is Enum;
isPSObject = source.ImmediateBaseObject is PSObject;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ protected override void ProcessRecord()
Adapter staticAdapter = null;
if (this.Static == true)
{
staticAdapter = PSObject.dotNetStaticAdapter;
staticAdapter = PSObject.DotNetStaticAdapter;
object baseObject = this.InputObject.BaseObject;
baseObjectAsType = baseObject as System.Type ?? baseObject.GetType();
typeName = baseObjectAsType.FullName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ private static object ProcessValue(object obj, int currentDepth, in ConvertToJso
{
if (currentDepth > context.MaxDepth)
{
if (pso != null && pso.immediateBaseObjectIsEmpty)
if (pso != null && pso.ImmediateBaseObjectIsEmpty)
{
// The obj is a pure PSObject, we convert the original PSObject to a string,
// instead of its base object in this case
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1975,9 +1975,10 @@ private void ReportException(Exception e, Executor exec)
error = (object)new ErrorRecord(e, "ConsoleHost.ReportException", ErrorCategory.NotSpecified, null);
}

PSObject wrappedError = new PSObject(error);
PSNoteProperty note = new PSNoteProperty("writeErrorStream", true);
wrappedError.Properties.Add(note);
PSObject wrappedError = new PSObject(error)
{
WriteStream = WriteStreamType.Error
};

Exception e1 = null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ private void WritePayloadObject(PSObject so)
{
Diagnostics.Assert(so != null, "object so cannot be null");
FormatEntryData fed = _viewManager.ViewGenerator.GeneratePayload(so, _enumerationLimit);
fed.SetStreamTypeFromPSObject(so);
fed.writeStream = so.WriteStream;
this.WriteObject(fed);

List<ErrorRecord> errors = _viewManager.ViewGenerator.ErrorManager.DrainFailedResultList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -464,65 +464,19 @@ private static ViewGenerator SelectViewGeneratorFromProperties(FormatShape shape
/// </summary>
internal static class OutOfBandFormatViewManager
{
internal static bool IsPropertyLessObject(PSObject so)
private static bool IsNotRemotingProperty(string name)
{
List<MshResolvedExpressionParameterAssociation> allProperties = AssociationManager.ExpandAll(so);

if (allProperties.Count == 0)
{
return true;
}

if (allProperties.Count == 3)
{
foreach (MshResolvedExpressionParameterAssociation property in allProperties)
{
if (!property.ResolvedExpression.ToString().Equals(RemotingConstants.ComputerNameNoteProperty, StringComparison.OrdinalIgnoreCase) &&
!property.ResolvedExpression.ToString().Equals(RemotingConstants.ShowComputerNameNoteProperty, StringComparison.OrdinalIgnoreCase) &&
!property.ResolvedExpression.ToString().Equals(RemotingConstants.RunspaceIdNoteProperty, StringComparison.OrdinalIgnoreCase))
{
return false;
}
}

return true;
}

if (allProperties.Count == 4)
{
foreach (MshResolvedExpressionParameterAssociation property in allProperties)
{
if (!property.ResolvedExpression.ToString().Equals(RemotingConstants.ComputerNameNoteProperty, StringComparison.OrdinalIgnoreCase) &&
!property.ResolvedExpression.ToString().Equals(RemotingConstants.ShowComputerNameNoteProperty, StringComparison.OrdinalIgnoreCase) &&
!property.ResolvedExpression.ToString().Equals(RemotingConstants.RunspaceIdNoteProperty, StringComparison.OrdinalIgnoreCase)
&& !property.ResolvedExpression.ToString().Equals(RemotingConstants.SourceJobInstanceId, StringComparison.OrdinalIgnoreCase))
{
return false;
}
}

return true;
}

if (allProperties.Count == 5)
{
foreach (MshResolvedExpressionParameterAssociation property in allProperties)
{
if (!property.ResolvedExpression.ToString().Equals(RemotingConstants.ComputerNameNoteProperty, StringComparison.OrdinalIgnoreCase) &&
!property.ResolvedExpression.ToString().Equals(RemotingConstants.ShowComputerNameNoteProperty, StringComparison.OrdinalIgnoreCase) &&
!property.ResolvedExpression.ToString().Equals(RemotingConstants.RunspaceIdNoteProperty, StringComparison.OrdinalIgnoreCase) &&
!property.ResolvedExpression.ToString().Equals(RemotingConstants.SourceJobInstanceId, StringComparison.OrdinalIgnoreCase) &&
!property.ResolvedExpression.ToString().Equals(RemotingConstants.SourceLength, StringComparison.OrdinalIgnoreCase))
{
return false;
}
}
var isRemotingPropertyName = name.Equals(RemotingConstants.ComputerNameNoteProperty, StringComparison.OrdinalIgnoreCase)
|| name.Equals(RemotingConstants.ShowComputerNameNoteProperty, StringComparison.OrdinalIgnoreCase)
|| name.Equals(RemotingConstants.RunspaceIdNoteProperty, StringComparison.OrdinalIgnoreCase)
|| name.Equals(RemotingConstants.SourceJobInstanceId, StringComparison.OrdinalIgnoreCase)
|| name.Equals(RemotingConstants.SourceLength, StringComparison.OrdinalIgnoreCase);
return !isRemotingPropertyName;
}

return true;
}
private static readonly MemberNamePredicate NameIsNotRemotingProperty = IsNotRemotingProperty;

return false;
}
private static bool HasNonRemotingProperties(PSObject so) => so.GetFirstPropertyOrDefault(NameIsNotRemotingProperty) != null;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

OK, I guess all the predicate overloads I saw above are for the purpose of supporting this operation, right?
So that you don't need to collect all properties in order to tell if the PSObject has a non-remoting property, is that correct?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yes, that is where most of the speedup comes from. We where getting all properties to see if we had any, and we did so for all objects. Hence my comment above about the possibility to cache this per type.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

That was what started the whole chain of changes. Getting a fast, low-allocation, way of satisfying the demands the formatting system has on the object model. It took up a huge chunk of the total time budget. After these changes, the time is spent doing actual formatting of the objects.

There are probably things to look at there to, but that is for another day :)


internal static FormatEntryData GenerateOutOfBandData(TerminatingErrorContext errorContext, PSPropertyExpressionFactory expressionFactory,
TypeInfoDataBase db, PSObject so, int enumerationLimit, bool useToStringFallback, out List<ErrorRecord> errors)
Expand All @@ -549,8 +503,8 @@ internal static FormatEntryData GenerateOutOfBandData(TerminatingErrorContext er
}
else
{
if (DefaultScalarTypes.IsTypeInList(typeNames) ||
IsPropertyLessObject(so))
if (DefaultScalarTypes.IsTypeInList(typeNames)
|| !HasNonRemotingProperties(so))
{
// we force a ToString() on well known types
return GenerateOutOfBandObjectAsToString(so);
Expand All @@ -575,7 +529,7 @@ internal static FormatEntryData GenerateOutOfBandData(TerminatingErrorContext er

FormatEntryData fed = outOfBandViewGenerator.GeneratePayload(so, enumerationLimit);
fed.outOfBand = true;
fed.SetStreamTypeFromPSObject(so);
fed.writeStream = so.WriteStream;

errors = outOfBandViewGenerator.ErrorManager.DrainFailedResultList();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
//

using System.Collections.Generic;
using System.Management.Automation;
Comment thread
powercode marked this conversation as resolved.

namespace Microsoft.PowerShell.Commands.Internal.Format
{
Expand Down Expand Up @@ -149,40 +150,6 @@ internal sealed partial class FormatEntryData : PacketInfoData
public bool outOfBand = false;
public WriteStreamType writeStream = WriteStreamType.None;
internal bool isHelpObject = false;

/// <summary>
/// Helper method to set the WriteStreamType property
/// based on note properties of a PSObject object.
/// </summary>
/// <param name="so">PSObject.</param>
internal void SetStreamTypeFromPSObject(
System.Management.Automation.PSObject so)
{
if (PSObjectHelper.IsWriteErrorStream(so))
{
writeStream = WriteStreamType.Error;
}
else if (PSObjectHelper.IsWriteWarningStream(so))
{
writeStream = WriteStreamType.Warning;
}
else if (PSObjectHelper.IsWriteVerboseStream(so))
{
writeStream = WriteStreamType.Verbose;
}
else if (PSObjectHelper.IsWriteDebugStream(so))
{
writeStream = WriteStreamType.Debug;
}
else if (PSObjectHelper.IsWriteInformationStream(so))
{
writeStream = WriteStreamType.Information;
}
else
{
writeStream = WriteStreamType.None;
}
}
}
#endregion

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,6 @@ protected int GetSplitLengthInternalHelper(string str, int offset, int displayCe

}

/// <summary>
/// Specifies special stream write processing.
/// </summary>
internal enum WriteStreamType
{
None,
Error,
Warning,
Verbose,
Debug,
Information
}

/// <summary>
/// Base class providing information about the screen device capabilities
/// and used to write the output strings to the text output device.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,81 +35,6 @@ internal static bool PSObjectIsEnum(Collection<string> typeNames)
return string.Equals(typeNames[1], "System.Enum", StringComparison.Ordinal);
}

/// <summary>
/// WriteError adds a note property called WriteErrorStream to the error
/// record wrapped in an PSObject and set its value to true. When F and O detects
/// this note exists and its value is set to true, WriteErrorLine will be used
/// to emit the error; otherwise, F and O actions are regular.
/// </summary>
/// <param name="so"></param>
/// <returns></returns>
internal static bool IsWriteErrorStream(PSObject so)
{
return IsStreamType(so, "WriteErrorStream");
}

/// <summary>
/// Checks for WriteWarningStream property on object, indicating that
/// it is a warning stream. Used by F and O.
/// </summary>
/// <param name="so"></param>
/// <returns></returns>
internal static bool IsWriteWarningStream(PSObject so)
{
return IsStreamType(so, "WriteWarningStream");
}

/// <summary>
/// Checks for WriteVerboseStream property on object, indicating that
/// it is a verbose stream. Used by F and O.
/// </summary>
/// <param name="so"></param>
/// <returns></returns>
internal static bool IsWriteVerboseStream(PSObject so)
{
return IsStreamType(so, "WriteVerboseStream");
}

/// <summary>
/// Checks for WriteDebugStream property on object, indicating that
/// it is a debug stream. Used by F and O.
/// </summary>
/// <param name="so"></param>
/// <returns></returns>
internal static bool IsWriteDebugStream(PSObject so)
{
return IsStreamType(so, "WriteDebugStream");
}

/// <summary>
/// Checks for WriteInformationStream property on object, indicating that
/// it is an informational stream. Used by F and O.
/// </summary>
/// <param name="so"></param>
/// <returns></returns>
internal static bool IsWriteInformationStream(PSObject so)
{
return IsStreamType(so, "WriteInformationStream");
}

internal static bool IsStreamType(PSObject so, string streamFlag)
{
try
{
PSPropertyInfo streamProperty = so.Properties[streamFlag];
if (streamProperty != null && streamProperty.Value is bool)
{
return (bool)streamProperty.Value;
}

return false;
}
catch (ExtendedTypeSystemException)
{
return false;
}
}

/// <summary>
/// Retrieve the display name. It looks for a well known property and,
/// if not found, it uses some heuristics to get a "close" match.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,44 @@ public override PSAdaptedProperty GetProperty(object baseObject, string property
return null;
}

/// <inheritdoc />
public override PSAdaptedProperty GetFirstPropertyOrDefault(object baseObject, MemberNamePredicate predicate)
{
if (predicate == null)
{
throw new PSArgumentNullException(nameof(predicate));
}

// baseObject should never be null
CimInstance cimInstance = baseObject as CimInstance;
if (cimInstance == null)
{
string msg = string.Format(
CultureInfo.InvariantCulture,
CimInstanceTypeAdapterResources.BaseObjectNotCimInstance,
"baseObject",
typeof(CimInstance).ToString());
throw new PSInvalidOperationException(msg);
}

if (predicate(RemotingConstants.ComputerNameNoteProperty))
{
PSAdaptedProperty prop = GetPSComputerNameAdapter(cimInstance);
return prop;
}

foreach (CimProperty cimProperty in cimInstance.CimInstanceProperties)
{
if (cimProperty != null && predicate(cimProperty.Name))
{
PSAdaptedProperty prop = GetCimPropertyAdapter(cimProperty, baseObject, cimProperty.Name);
return prop;
}
}

return null;
}

internal static string CimTypeToTypeNameDisplayString(CimType cimType)
{
switch (cimType)
Expand Down
Loading