Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
dbd1878
Add ability to parse `-settingsfile` before a console host is created
TravisEz13 Aug 4, 2018
10943a5
Parse the settings file before the console host is actually created
TravisEz13 Aug 4, 2018
3391e14
do not set snap in logging information on Unix
TravisEz13 Aug 4, 2018
1e673d3
re-enable tests
TravisEz13 Aug 4, 2018
5979c49
update to the latest mac image which most closely matches our release…
TravisEz13 Aug 4, 2018
4086976
change OsLogIds to a class, update ids, and add function to switch to…
TravisEz13 Aug 4, 2018
7d04ee2
add comments about fields
TravisEz13 Aug 4, 2018
e708a43
change OsLogIds to a class, update ids, and add function to switch to…
TravisEz13 Aug 4, 2018
05eed04
update export-psoslog so that it can also filter on PID
TravisEz13 Aug 4, 2018
1e9d32d
move test to feature as it was not 100% reliable in my testing
TravisEz13 Aug 4, 2018
2226218
update tests to filter logs on pid
TravisEz13 Aug 4, 2018
b2d36a8
update test to use count as I found it more reliable
TravisEz13 Aug 4, 2018
96e0b52
add workaround for logs not showing up reliably
TravisEz13 Aug 5, 2018
5c48dbc
Address CodeFactor issues
TravisEz13 Aug 5, 2018
777f5eb
Update GetSwitchKey to return a NamedTuple instead of using an out pa…
TravisEz13 Aug 5, 2018
e9fd826
indent regions
TravisEz13 Aug 5, 2018
4f1f4f0
simplify logic in MasterSwitch metod
TravisEz13 Aug 5, 2018
8ca2220
Rename ParseSettingFileHelper method TryParseSettingFileHelper
TravisEz13 Aug 5, 2018
ed941fa
simply GetConfigurationNameFromGroupPolicy using `?:` and `.?` operators
TravisEz13 Aug 5, 2018
371ed6f
remove second clone of args
TravisEz13 Aug 5, 2018
92a8b9b
make sure linux and mac have seperate caches
TravisEz13 Aug 5, 2018
b8dcdfe
make switchKeyResults an explicit type
TravisEz13 Aug 6, 2018
6799d24
update comment about what parser is used for in GetSwitchKey
TravisEz13 Aug 6, 2018
d2a33ca
Address PR Comments
TravisEz13 Aug 6, 2018
00c2a10
Address PR Comments
TravisEz13 Aug 6, 2018
108ae7f
Address PR comment
TravisEz13 Aug 7, 2018
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
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ matrix:
dist: trusty
sudo: required
- os: osx
osx_image: xcode8.1
osx_image: xcode9.4
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I assume this means we won't be running tests against the prior OS version, right?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I found no differences in the log format, but yes correct

fast_finish: true

addons:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ internal CommandLineParameterParser(PSHostUserInterface hostUI, string bannerTex
_helpText = helpText;
}

#region Internal properties
internal bool AbortStartup
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Should #region be in position with the line?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

updated

{
get
Expand Down Expand Up @@ -392,6 +393,218 @@ internal string WorkingDirectory
{
get { return _workingDirectory; }
}
#endregion Internal properties

#region static methods
/// <summary>
/// Processes the -SettingFile Argument.
/// </summary>
/// <param name="args">
/// The command line parameters to be processed.
/// </param>
/// <param name="argIndex">
/// The index in args to the argument following '-SettingFile'.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The parameter name is generic but comment says that it is used only for '-SettingFile' - should the parameter name reflects the fact?

/// </param>
/// <param name="parser">
/// Used to allow the helper to write errors to the console. If not supplied, no errors will be written.
/// </param>
/// <returns>
/// Returns true if the argument was parsed successfully and false if not.
/// </returns>
private static bool ParseSettingFileHelper(string[] args, int argIndex, CommandLineParameterParser parser)
{
if (argIndex >= args.Length)
{
if (parser != null)
{
parser.WriteCommandLineError(
CommandLineParameterParserStrings.MissingSettingsFileArgument);
}

return false;
}

string configFile = null;
try
{
configFile = NormalizeFilePath(args[argIndex]);
}
catch (Exception ex)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I believe we could remove the try-catch. See my comment for NormalizeFilePath() method.

{
if (parser != null)
{
string error = string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.InvalidSettingsFileArgument, args[argIndex], ex.Message);
parser.WriteCommandLineError(error);
}

return false;
}

if (!System.IO.File.Exists(configFile))
{
if (parser != null)
{
string error = string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.SettingsFileNotExists, configFile);
parser.WriteCommandLineError(error);
}

return false;
}
PowerShellConfig.Instance.SetSystemConfigFilePath(configFile);
return true;
}

/// <summary>
/// Processes the command line parameters to ConsoleHost which must be parsed before the Host is created.
/// Success to indicate that the program should continue running.
/// </summary>
/// <param name="args">
/// The command line parameters to be processed.
/// </param>
internal static void EarlyParse(string[] args)
{
Dbg.Assert(!_dirtyEarlyParse, "This instance has already been used. Create a new instance.");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The assert message is misleading. The method can only be called once since _dirtyEarlyParse is a static field.
Additionally, back this up with a release test or simply return if true. We don't run debug tests enough to catch this problem.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

removed, I verified this can be run multiple times


// indicates that we've called this method on this instance, and that when it's done, the state variables
// will reflect the parse.
_dirtyEarlyParse = true;

EarlyParseHelper(args);
}

private static string GetConfigurationNameFromGroupPolicy()
{
// Current user policy takes precedence.
var consoleSessionSetting = Utils.GetPolicySetting<ConsoleSessionConfiguration>(Utils.CurrentUserThenSystemWideConfig);
if (consoleSessionSetting != null)
{
if (consoleSessionSetting.EnableConsoleSessionConfiguration == true)
{
if (!string.IsNullOrEmpty(consoleSessionSetting.ConsoleSessionConfigurationName))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We could combine three if in one or use ? operator in just single return.

{
return consoleSessionSetting.ConsoleSessionConfigurationName;
}
}
}

return string.Empty;
}

/// <summary>
/// Processes the command line parameters to ConsoleHost which must be parsed before the Host is created.
/// Success to indicate that the program should continue running.
/// </summary>
/// <param name="args">
/// The command line parameters to be processed.
/// </param>
private static void EarlyParseHelper(string[] args)
{
Dbg.Assert(args != null, "Argument 'args' to ParseHelper should never be null");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Back this up with a check in release mode. At a minimum, silently ignore and return.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

resolved

bool noexitSeen = false;
for (int i = 0; i < args.Length; ++i)
{
var switchKeyResults = GetSwitchKey(args, ref i, null, ref noexitSeen);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It is not clear that we get from the method. I'd replace var with explicit type.
Can we use:

(string switchKey, bool shouldBreak) = GetSwitchKey(args, ref i, null, ref noexitSeen); 

Named argument for null will be good.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

resolved

if (switchKeyResults.ShouldBreak)
{
break;
}

string switchKey = switchKeyResults.SwitchKey;

if (MatchSwitch(switchKey, "settingsfile", "settings"))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Named arguments will be good for constants. Below I see some such patterns.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

resolved

{
// parse setting file arg and don't write error as there is no host yet.
if (!ParseSettingFileHelper(args, ++i, null))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Maybe use TryParseSettingFileHelper?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

updated

{
break;
}
}
}
}

/// <summary>
/// Gets the word in a switch from the current argument or parses a file.
/// For example -foo, /foo, or --foo would return 'foo'.
/// </summary>
/// <param name="args">
/// The command line parameters to be processed.
/// </param>
/// <param name="argIndex">
/// The index in args to the argument to process.
/// </param>
/// <param name="parser">
/// Used to allow the helper to write errors to the console. If not supplied, Files will not be parsed.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The comment about writing errors doesn't appear to apply.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Updated comment (I have not pushed at this point.)

/// </param>
/// <param name="noexitSeen">
/// Used during parsing files.
/// </param>
/// <returns>
/// Returns a Tuple:
/// The first value is a String called SwitchKey with the word in a switch from the current argument or null.
/// The second value is a bool called ShouldBreak, indicating if the parsing look should break.
/// </returns>
private static (string SwitchKey, bool ShouldBreak) GetSwitchKey(string[] args, ref int argIndex, CommandLineParameterParser parser, ref bool noexitSeen)
{
string switchKey = args[argIndex].Trim().ToLowerInvariant();
if (string.IsNullOrEmpty(switchKey))
{
return (SwitchKey: null, ShouldBreak: false);
}

if (!SpecialCharacters.IsDash(switchKey[0]) && switchKey[0] != '/')
{
// then its a file
if (parser != null)
{
--argIndex;
parser.ParseFile(args, ref argIndex, noexitSeen);
}

return (SwitchKey: null, ShouldBreak: true);
}

// chop off the first character so that we're agnostic wrt specifying / or -
// in front of the switch name.
switchKey = switchKey.Substring(1);

// chop off the second dash so we're agnostic wrt specifying - or --
if (!string.IsNullOrEmpty(switchKey) && SpecialCharacters.IsDash(switchKey[0]))
{
switchKey = switchKey.Substring(1);
}

return (SwitchKey: switchKey, ShouldBreak: false);
}

private static string NormalizeFilePath(string path)
{
// Normalize slashes
path = path.Replace(StringLiterals.AlternatePathSeparator,
StringLiterals.DefaultPathSeparator);

return Path.GetFullPath(path);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The method is used once and then we call File.Exist() where Path.GetFullPath() is called again.
https://source.dot.net/#System.IO.FileSystem/System/IO/File.cs,119
We could simplify the TryParseSettingFileHelper() method - remove try-catch there (line 429), move the line 574 to TryParseSettingFileHelper() before File.Exist()

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

existing code, please file an issue, the method was just changed from an instance to static

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Done #7469.

}

private static bool MatchSwitch(string switchKey, string match, string smallestUnambiguousMatch)
{
Dbg.Assert(switchKey != null, "need a value");
Dbg.Assert(!String.IsNullOrEmpty(match), "need a value");
Dbg.Assert(match.Trim().ToLowerInvariant() == match, "match should be normalized to lowercase w/ no outside whitespace");
Dbg.Assert(smallestUnambiguousMatch.Trim().ToLowerInvariant() == smallestUnambiguousMatch, "match should be normalized to lowercase w/ no outside whitespace");
Dbg.Assert(match.Contains(smallestUnambiguousMatch), "sUM should be a substring of match");

if (match.Trim().ToLowerInvariant().IndexOf(switchKey, StringComparison.Ordinal) == 0)
{
if (switchKey.Length >= smallestUnambiguousMatch.Length)
{
return true;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We could exclude if-s and use single return.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

sorry, I don't follow what you are saying.

Well, looking at the code, I made a guess.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I meant

return (match.Trim().ToLowerInvariant().IndexOf(switchKey, StringComparison.Ordinal) == 0) && (switchKey.Length >= smallestUnambiguousMatch.Length)

}
}

return false;
}

#endregion

private void ShowHelp()
{
Expand Down Expand Up @@ -463,57 +676,20 @@ internal void Parse(string[] args)
}
}

private static string GetConfigurationNameFromGroupPolicy()
{
// Current user policy takes precedence.
var consoleSessionSetting = Utils.GetPolicySetting<ConsoleSessionConfiguration>(Utils.CurrentUserThenSystemWideConfig);
if (consoleSessionSetting != null)
{
if (consoleSessionSetting.EnableConsoleSessionConfiguration == true)
{
if (!string.IsNullOrEmpty(consoleSessionSetting.ConsoleSessionConfigurationName))
{
return consoleSessionSetting.ConsoleSessionConfigurationName;
}
}
}

return string.Empty;
}

private void ParseHelper(string[] args)
{
Dbg.Assert(args != null, "Argument 'args' to ParseHelper should never be null");
bool noexitSeen = false;

for (int i = 0; i < args.Length; ++i)
{
// Invariant culture used because command-line parameters are not localized.

string switchKey = args[i].Trim().ToLowerInvariant();
if (String.IsNullOrEmpty(switchKey))
var switchKeyResults = GetSwitchKey(args, ref i, this, ref noexitSeen);
if (switchKeyResults.ShouldBreak)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm pretty sure tuple field names are case sensitive.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

updated

{
continue;
}

if (!SpecialCharacters.IsDash(switchKey[0]) && switchKey[0] != '/')
{
// then its a file

--i;
ParseFile(args, ref i, noexitSeen);
break;
}

// chop off the first character so that we're agnostic wrt specifying / or -
// in front of the switch name.
switchKey = switchKey.Substring(1);

// chop off the second dash so we're agnostic wrt specifying - or --
if (!String.IsNullOrEmpty(switchKey) && SpecialCharacters.IsDash(switchKey[0]))
{
switchKey = switchKey.Substring(1);
}
string switchKey = switchKeyResults.SwitchKey;

// If version is in the commandline, don't continue to look at any other parameters
if (MatchSwitch(switchKey, "version", "v"))
Expand Down Expand Up @@ -711,34 +887,13 @@ private void ParseHelper(string[] args)
}
}

else if (MatchSwitch(switchKey, "settingsfile", "settings") )
else if (MatchSwitch(switchKey, "settingsfile", "settings"))
{
++i;
if (i >= args.Length)
// Parse setting file arg and write error
if (!ParseSettingFileHelper(args, ++i, this))
{
WriteCommandLineError(
CommandLineParameterParserStrings.MissingSettingsFileArgument);
break;
}
string configFile = null;
try
{
configFile = NormalizeFilePath(args[i]);
}
catch (Exception ex)
{
string error = string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.InvalidSettingsFileArgument, args[i], ex.Message);
WriteCommandLineError(error);
break;
}

if (!System.IO.File.Exists(configFile))
{
string error = string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.SettingsFileNotExists, configFile);
WriteCommandLineError(error);
break;
}
PowerShellConfig.Instance.SetSystemConfigFilePath(configFile);
}
#if STAMODE
// explicit setting of the ApartmentState Not supported on NanoServer
Expand Down Expand Up @@ -818,25 +973,6 @@ private void WriteCommandLineError(string msg, bool showHelp = false, bool showB
_exitCode = ConsoleHost.ExitCodeBadCommandLineParameter;
}

private bool MatchSwitch(string switchKey, string match, string smallestUnambiguousMatch)
{
Dbg.Assert(switchKey != null, "need a value");
Dbg.Assert(!String.IsNullOrEmpty(match), "need a value");
Dbg.Assert(match.Trim().ToLowerInvariant() == match, "match should be normalized to lowercase w/ no outside whitespace");
Dbg.Assert(smallestUnambiguousMatch.Trim().ToLowerInvariant() == smallestUnambiguousMatch, "match should be normalized to lowercase w/ no outside whitespace");
Dbg.Assert(match.Contains(smallestUnambiguousMatch), "sUM should be a substring of match");

if (match.Trim().ToLowerInvariant().IndexOf(switchKey, StringComparison.Ordinal) == 0)
{
if (switchKey.Length >= smallestUnambiguousMatch.Length)
{
return true;
}
}

return false;
}

private void ParseFormat(string[] args, ref int i, ref Serialization.DataFormat format, string resourceStr)
{
StringBuilder sb = new StringBuilder();
Expand Down Expand Up @@ -892,15 +1028,6 @@ private void ParseExecutionPolicy(string[] args, ref int i, ref string execution
executionPolicy = args[i];
}

private static string NormalizeFilePath(string path)
{
// Normalize slashes
path = path.Replace(StringLiterals.AlternatePathSeparator,
StringLiterals.DefaultPathSeparator);

return Path.GetFullPath(path);
}

private bool ParseFile(string[] args, ref int i, bool noexitSeen)
{
// Process file execution. We don't need to worry about checking -command
Expand Down Expand Up @@ -1201,6 +1328,7 @@ private bool CollectArgs(string[] args, ref int i)
return true;
}

private static bool _dirtyEarlyParse;
private bool _socketServerMode;
private bool _serverMode;
private bool _namedPipeServerMode;
Expand Down
Loading