Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Convert compatibility module to binary module, fix compatibility with Azure environments#1212

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
JamesWTruher merged 74 commits intoPowerShell:developmentfromrjmholt:azf-compat
May 10, 2019

Conversation

@rjmholt
Copy link
Contributor

@rjmholtrjmholt commentedApr 8, 2019
edited
Loading

PR Summary

Resolves#1149.

The original compatibility check module was hastily implemented and was quite slow. It also needed CIM/WMI to be available. This meant it didn't work nicely with things like Azure Functions.

I rewrote it as a binary to be faster and to have a simpler, more composable, more semantically definite .NET API.

There are a bunch of breaking changes with the compatibility types here (which are technically exposed by PSSA). There are also huge breaking changes in the PSCompatibilityAnalyzer module (I got rid of most of the commands), but that has never been released and is still below version 1.0, so that seems like less of a concern.

Basically there are no changes that break the PowerShell API of PSScriptAnalyzer unless people have gone hunting for types that are loaded (but aren't used directly by the module).

Also renames the PSCompatibilityAnalyzer module to PSCompatibilityCollector since that's more accurate and less confusing.

List of changes

  • Renamed PSCompatibilityAnalyzer to PSCompatibilityCollector, since that better describes what the module does. The module is now version 0.2.0.
  • Got rid of almost all the psm1 module implementation in favour of a binary module. This gets rid of all the command originally in that module in favour of a minimal set of cmdlets with a common noun prefix.
  • Added explicit JSON configuration to the serialiser. Extra fields in JSON are now explicitly ignored (this is the default, so the behaviour has not changed), and default values are now explicitly omitted from JSON and restored in C# when absent (again, this should not change any behaviours)
  • Added a JSON schema version, with a default version of 1.0. The current generated schema version is 1.1 (since there are additions but not breaking changes, breaking changes should start at 2.0)
  • Flattened the Query and Data namespaces. The Query namespace was already mostly like this. It made sense to me to flatten it all from a complexity standpoint.
  • Change theConstituentProfiles field to be aReadOnlySet<string> instead of aHashSet<string>
  • Change type dictionaries to be case-sensitive for collection and overriding (like PowerShell) for the query API (this is already done inPrevent .NET members with names differing only by case from crashing the compatibility profiler #1195, but I need it on my machine). WhenPrevent .NET members with names differing only by case from crashing the compatibility profiler #1195 is merged, I'll rebase this on top.
  • Move things out of theMicrosoft.PowerShell.CrossCompatibility.Utility namespace and into the base namespace,Collection orRetrieval depending on what the class does, since I thinkUtility should be reserved for internal helpers
  • Omit the pre-existing profiles from the output PSCompatibilityCollector module, since they aren't needed for collection
  • Add profiles for Azure Functions and Azure Automation

PR Checklist

@rjmholtrjmholt changed the titleWIP: Convert compatibility module to binary module, fix compatibility with Azure environmentsConvert compatibility module to binary module, fix compatibility with Azure environmentsApr 9, 2019
@bergmeister
Copy link
Collaborator

@rjmholt I'm overall OK with the changes as they are mainly just in your module. But I think@JamesWTruher would be the better person to review the logic, etc. as he has more experience/knowledge in this area.

rjmholt reacted with thumbs up emoji

@bergmeisterbergmeister removed their request for reviewApril 15, 2019 20:47
rjmholtand others added23 commitsApril 24, 2019 14:46
Copy link
Contributor

@JamesWTruherJamesWTruher left a comment

Choose a reason for hiding this comment

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

here's the first of my comments

/// Add path prefixes of modules to exclude.
/// </summary>
/// <param name="modulePrefixes">Path prefixes of modules to exclude.</param>
publicBuilderExcludedModulePathPrefixes(IReadOnlyCollection<string>modulePrefixes)
Copy link
Contributor

Choose a reason for hiding this comment

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

is there a reason why some of these aren't a void return? I see that you don't use the return value where you call it.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Just a convention of the builder pattern I've always used, but looking at thewikipedia page it seems to be less of a thing in C#. I'll change it over to just use simple properties.

/// <returns>An object containing common feature compatibility information.</returns>
publicCommonPowerShellDataGetCommonPowerShellData()
{
CmdletInfogcmInfo=_pwsh.AddCommand(PowerShellDataCollector.GcmInfo)
Copy link
Contributor

Choose a reason for hiding this comment

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

we really need a better way to do this (get a command)

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

It's possible without the info object (since some commands might be loaded dynamically or are defined in script), but@daxian-dbw told me that providing the info object makes it faster.

_pwsh.Dispose();
_platformInfoCollector.Dispose();
_pwshDataCollector.Dispose();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

does dispose order matter here?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

I never quite know about dispose order. Theoretically, since they are all co-dependent, the outer one should dispose the inner ones, but I tend to dispose from inside -> out. Perhaps it should be the other way round?

osData.DistributionId=lsbInfo["DistributionId"];
osData.DistributionVersion=lsbInfo["DistributionVersion"];
osData.DistributionPrettyName=lsbInfo["DistributionPrettyName"];
break;
Copy link
Contributor

Choose a reason for hiding this comment

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

no mac?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Looking on macOS now, we might want an extra field for the retail version (i.e. the macOS version rather than the darwin version), but I'll add that later I think. For now, a macOS platform is identified concretely bymacOS and the darwin kernel version I think.


try
{
functionData.ParameterSets=GetParameterSets(function.ParameterSets);
Copy link
Contributor

Choose a reason for hiding this comment

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

same

/// </summary>
/// <param name="variables">Variables to collect information on.</param>
/// <returns>An array of the names of the variables.</returns>
publicstring[]GetVariablesData(IEnumerable<PSVariable>variables)
Copy link
Contributor

Choose a reason for hiding this comment

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

GetVariablesName?

for(inti=0;i<outputTypeData.Length;i++)
{
outputTypeData[i]=outputType[i].Type!=null
?TypeNaming.GetFullTypeName(outputType[i].Type)
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 assuming this is where it can throw

privatestaticReadOnlySet<string>GetPowerShellCommonParameterNames()
{
varset=newList<string>();
foreach(PropertyInfopropertyintypeof(CommonParameters).GetProperties())
Copy link
Contributor

Choose a reason for hiding this comment

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

GetProperties(Public,Instance,DeclaredOnly)?

rjmholt reacted with thumbs up emoji
Type[]types=asm.GetTypes();
JsonDictionary<string,JsonDictionary<string,TypeData>>namespacedTypes=null;
if(types.Any())
if(types.Length>0)
Copy link
Contributor

Choose a reason for hiding this comment

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

in line 193, why not usetypes from line 188?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Good catch!

/// Add path prefixes of modules to exclude.
/// </summary>
/// <param name="modulePrefixes">Path prefixes of modules to exclude.</param>
publicBuilderExcludedModulePathPrefixes(IReadOnlyCollection<string>modulePrefixes)
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Just a convention of the builder pattern I've always used, but looking at thewikipedia page it seems to be less of a thing in C#. I'll change it over to just use simple properties.

/// <returns>An object containing common feature compatibility information.</returns>
publicCommonPowerShellDataGetCommonPowerShellData()
{
CmdletInfogcmInfo=_pwsh.AddCommand(PowerShellDataCollector.GcmInfo)
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

It's possible without the info object (since some commands might be loaded dynamically or are defined in script), but@daxian-dbw told me that providing the info object makes it faster.

_pwsh.Dispose();
_platformInfoCollector.Dispose();
_pwshDataCollector.Dispose();
}
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

I never quite know about dispose order. Theoretically, since they are all co-dependent, the outer one should dispose the inner ones, but I tend to dispose from inside -> out. Perhaps it should be the other way round?

osData.DistributionId=lsbInfo["DistributionId"];
osData.DistributionVersion=lsbInfo["DistributionVersion"];
osData.DistributionPrettyName=lsbInfo["DistributionPrettyName"];
break;
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Looking on macOS now, we might want an extra field for the retail version (i.e. the macOS version rather than the darwin version), but I'll add that later I think. For now, a macOS platform is identified concretely bymacOS and the darwin kernel version I think.


privateconststringTHIS_MODULE_NAME="PSCompatibilityCollector";

privatestaticreadonlyRegexs_typeDataRegex=newRegex("Error in TypeData\"([A-Za-z.]+)\"",RegexOptions.Compiled);
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Good catch. There's a kind of error PowerShell emits when two modules have conflicting TypeData and the only way to identify it is by parsing the error message.

// Get default variables and core aliases out of a fresh runspace
using(SMA.PowerShellfreshPwsh=SMA.PowerShell.Create(RunspaceMode.NewRunspace))
{
Collection<PSVariable>defaultVariables=freshPwsh.AddCommand("Get-ChildItem")
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Not a bad idea


try
{
functionData.OutputType=GetOutputType(function.OutputType);
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Actually, I think this occurs at thefunction.OutputType point, when we fire the getter, because it has tofind the type


try
{
functionData.OutputType=GetOutputType(function.OutputType);
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

I'm going to leave this one for now. The real question in my mind was how much data do we want to record about the function that throws when we try to load information about it. But for now I think just the skeleton is ok.

Type[]types=asm.GetTypes();
JsonDictionary<string,JsonDictionary<string,TypeData>>namespacedTypes=null;
if(types.Any())
if(types.Length>0)
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Good catch!

/// <summary>
/// The verison of the profile schema this profile object uses.
/// </summary>
[DataMember]
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

I tried a few ways to set the automatic value of this to 1.0, but I couldn't work out how; I can't specify a version in the attribute.

/// If set, do not include whitespace like indentation or newlines in the output JSON.
/// </summary>
[Parameter]
[Alias("Compress")]
Copy link
Contributor

Choose a reason for hiding this comment

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

do you think this alias will suggest that it will create an actual compressed (.zip) file?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

I actually put this in becauseConvertTo-Json calls thisCompress, but left it an alias because I think it's a bad name for it

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Happy to go either way on this btw

return;

default:
thrownewArgumentException($"Unsupported type for{nameof(JsonSource)} parameter. Should be a string, FileInfo or TextReader object.");
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should probably be aWriteError because it takes a collection of objects so one bad one should not cause the pipeline to abort. Also, if it should be terminating, then you probably wantThrowTerminatingError

rjmholt reacted with thumbs up emoji
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Ah ok! Is it possible to throw multiple terminating errors?

[Parameter]
publicDotnetDataDotNet{get;set;}

protectedoverridevoidEndProcessing()
Copy link
Contributor

Choose a reason for hiding this comment

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

do you see a scenario where this would be called iteratively? If so, it should probably be inProcessRecord

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

I thought about that, but because there are no pipeline parameters and it's probably used for collecting a profile on the local machine,EndProcessing seemed like the right call. This is effectively a function rather than a filter

}

// If PassThru is set, just pass the object back and we're done
if(PassThru)
Copy link
Contributor

Choose a reason for hiding this comment

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

PassThru is usually used more like/bin/tee where the datais returnedand the targets are created.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Yeah I was thinking about that. Maybe I should change this parameter name? Nothing else common really captures the behaviour though

Copy link
Contributor

Choose a reason for hiding this comment

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

yah, probably, but later before we release and have time to think of a better parameter name

usingSystem.Collections;
usingSystem.Collections.Generic;

namespaceMicrosoft.PowerShell.CrossCompatibility
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if this has enough utility to be part of PowerShell (or .NET)

Copy link
ContributorAuthor

@rjmholtrjmholtApr 25, 2019
edited
Loading

Choose a reason for hiding this comment

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

It really should be somewhere, I've wanted it a few times


namespaceMicrosoft.PowerShell.CrossCompatibility.Utility
{
internalstaticclassPowerShellExtensions
Copy link
Contributor

Choose a reason for hiding this comment

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

Ireally think this should be in PowerShell (it doesn't much help with down level), but it's a common pattern which we could easily improve for folks.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Agreed. I'm not really sure how you're supposed to reuse a PowerShell instance without this. As in, I don't really understand the default scenario.

/// <summary>
/// Class defining the Assert-PSCompatibilityProfileIsValid cmdlet.
/// </summary>
[Cmdlet(VerbsLifecycle.Assert,CommandUtilities.MODULE_PREFIX+"ProfileIsValid")]
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 also possible this could be the verbTest and returntrue orfalse

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Yeah I was weighing up those two. The problem is always that a boolean gives no diagnosis. I don't like that it throws an exception really, but it's better than a third custom solution

Copy link
Contributor

@JamesWTruherJamesWTruher left a comment

Choose a reason for hiding this comment

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

good to go

@JamesWTruherJamesWTruher merged commit064b622 intoPowerShell:developmentMay 10, 2019
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@daxian-dbwdaxian-dbwAwaiting requested review from daxian-dbw

@SteveL-MSFTSteveL-MSFTAwaiting requested review from SteveL-MSFT

1 more reviewer

@JamesWTruherJamesWTruherJamesWTruher approved these changes

Reviewers whose approvals may not affect merge requirements

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Convert PSCompatibilityAnalyzer module to a binary module

3 participants

@rjmholt@bergmeister@JamesWTruher

[8]ページ先頭

©2009-2025 Movatter.jp