Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ matrix:
- os: linux
dist: trusty
sudo: required
env: TRAVIS_CI_CACHE_NAME=linux
- os: osx
osx_image: xcode8.1
osx_image: xcode9.4
Copy link
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
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

env: TRAVIS_CI_CACHE_NAME=macOS
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
{
get
Expand Down Expand Up @@ -393,6 +394,205 @@ 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="settingFileArgIndex">
/// The index in args to the argument following '-SettingFile'.
/// </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 TryParseSettingFileHelper(string[] args, int settingFileArgIndex, CommandLineParameterParser parser)
{
if (settingFileArgIndex >= args.Length)
{
if (parser != null)
{
parser.WriteCommandLineError(
CommandLineParameterParserStrings.MissingSettingsFileArgument);
}

return false;
}

string configFile = null;
try
{
configFile = NormalizeFilePath(args[settingFileArgIndex]);
}
catch (Exception ex)
{
if (parser != null)
{
string error = string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.InvalidSettingsFileArgument, args[settingFileArgIndex], 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)
{
// indicates that we've called this method on this instance, and that when it's done, the state variables
// will reflect the parse.

EarlyParseHelper(args);
}

private static string GetConfigurationNameFromGroupPolicy()
{
// Current user policy takes precedence.
var consoleSessionSetting = Utils.GetPolicySetting<ConsoleSessionConfiguration>(Utils.CurrentUserThenSystemWideConfig);

return (consoleSessionSetting?.EnableConsoleSessionConfiguration == true && !string.IsNullOrEmpty(consoleSessionSetting?.ConsoleSessionConfigurationName)) ?
consoleSessionSetting.ConsoleSessionConfigurationName : string.Empty;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe use more short name like settings to get more short code strings.

Copy link
Member Author

Choose a reason for hiding this comment

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

this is an existing variable name. Please file an issues

}

/// <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)
{
if(args == null)
{
Dbg.Assert(args != null, "Argument 'args' to EarlyParseHelper should never be null");
return;
}

bool noexitSeen = false;
for (int i = 0; i < args.Length; ++i)
{
(string SwitchKey, bool ShouldBreak) switchKeyResults = GetSwitchKey(args, ref i, parser: null, ref noexitSeen);
if (switchKeyResults.ShouldBreak)
{
break;
}

string switchKey = switchKeyResults.SwitchKey;

if (MatchSwitch(switchKey, match: "settingsfile", smallestUnambiguousMatch: "settings"))
{
// parse setting file arg and don't write error as there is no host yet.
if (!TryParseSettingFileHelper(args, ++i, parser: null))
{
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 parse files in the args. If not supplied, Files will not be parsed.
/// </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
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
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
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");

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

#endregion

private void ShowHelp()
{
Dbg.Assert(_helpText != null, "_helpText should not be null");
Expand Down Expand Up @@ -463,57 +663,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))
(string SwitchKey, bool ShouldBreak) switchKeyResults = GetSwitchKey(args, ref i, this, ref noexitSeen);
if (switchKeyResults.ShouldBreak)
{
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 +874,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 (!TryParseSettingFileHelper(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 +960,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 +1015,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
8 changes: 6 additions & 2 deletions src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,12 @@ internal static int Start(

try
{
// We need to read the settings file before we create the console host
string[] tempArgs = new string[args.GetLength(0)];
args.CopyTo(tempArgs, 0);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could you please clarify why we need clone args?

Copy link
Member Author

Choose a reason for hiding this comment

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

The existing code cloned the args. I don't want to break something by not cloning.

Copy link
Member Author

Choose a reason for hiding this comment

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

Reviewing the code. I don't think it has to be. I especially don't think it has to be twice. compromise, I'll remove the second clone, you file an issue to remove the first one.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Done #7457.


CommandLineParameterParser.EarlyParse(tempArgs);
Copy link
Contributor

Choose a reason for hiding this comment

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

I've created issue #7460 to move this call to UnmanagedPSEntry.Start prior to PSEtwLog.LogConsoleStartup().

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks


// We might be able to ignore console host creation error if we are running in
// server mode, which does not require a console.
HostException hostException = null;
Expand All @@ -168,8 +174,6 @@ internal static int Start(
s_cpp = new CommandLineParameterParser(
(s_theConsoleHost != null) ? s_theConsoleHost.UI : (new NullHostUserInterface()),
bannerText, helpText);
string[] tempArgs = new string[args.GetLength(0)];
args.CopyTo(tempArgs, 0);

s_cpp.Parse(tempArgs);

Expand Down
Loading