/Microsoft.Scripting/Hosting/Shell/ConsoleHost.cs
C# | 453 lines | 334 code | 84 blank | 35 comment | 56 complexity | 4a8e8cd0e65a7f353a10f5eb9e4d424e MD5 | raw file
- /* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Microsoft Public License. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Microsoft Public License, please send an email to
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Microsoft Public License.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
- #if CODEPLEX_40
- using System;
- #else
- using System; using Microsoft;
- #endif
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.IO;
- using System.Reflection;
- using System.Runtime.CompilerServices;
- #if !CODEPLEX_40
- using Microsoft.Runtime.CompilerServices;
- #endif
-
- using System.Text;
- using System.Threading;
- using Microsoft.Scripting.Generation;
- using Microsoft.Scripting.Runtime;
- using Microsoft.Scripting.Utils;
-
- namespace Microsoft.Scripting.Hosting.Shell {
- /// <summary>
- /// Core functionality to implement an interactive console. This should be derived for concrete implementations
- /// </summary>
- public abstract class ConsoleHost {
- private int _exitCode;
- private ConsoleHostOptionsParser _optionsParser;
- private ScriptRuntime _runtime;
- private ScriptEngine _engine;
- internal OptionsParser _languageOptionsParser;
- private IConsole _console;
- private CommandLine _commandLine;
-
- public ConsoleHostOptions Options { get { return _optionsParser.Options; } }
- public ScriptRuntimeSetup RuntimeSetup { get { return _optionsParser.RuntimeSetup; } }
-
- public ScriptEngine Engine { get { return _engine; } protected set { _engine = value; } }
- public ScriptRuntime Runtime { get { return _runtime; } protected set { _runtime = value; } }
- protected int ExitCode { get { return _exitCode; } set { _exitCode = value; } }
- protected ConsoleHostOptionsParser ConsoleHostOptionsParser { get { return _optionsParser; } set { _optionsParser = value; } }
- protected IConsole ConsoleIO { get { return _console; } set { _console = value; } }
- protected CommandLine CommandLine { get { return _commandLine; } }
-
- protected ConsoleHost() {
- }
-
-
- /// <summary>
- /// Console Host entry-point .exe name.
- /// </summary>
- protected virtual string ExeName {
- get {
- #if !SILVERLIGHT
- Assembly entryAssembly = Assembly.GetEntryAssembly();
- //Can be null if called from unmanaged code (VS integration scenario)
- return entryAssembly != null ? entryAssembly.GetName().Name : "ConsoleHost";
- #else
- return "ConsoleHost";
- #endif
- }
- }
-
- #region Customization
-
- protected virtual void ParseHostOptions(string[] args) {
- _optionsParser.Parse(args);
- }
-
- protected virtual ScriptRuntimeSetup CreateRuntimeSetup() {
- var setup = ScriptRuntimeSetup.ReadConfiguration();
-
- string provider = Provider.AssemblyQualifiedName;
-
- if (!setup.LanguageSetups.Any(s => s.TypeName == provider)) {
- var languageSetup = CreateLanguageSetup();
- if (languageSetup != null) {
- setup.LanguageSetups.Add(languageSetup);
- }
- }
-
- return setup;
- }
-
- protected virtual LanguageSetup CreateLanguageSetup() {
- return null;
- }
-
- protected virtual PlatformAdaptationLayer PlatformAdaptationLayer {
- get { return PlatformAdaptationLayer.Default; }
- }
-
- protected virtual Type Provider {
- get { return null; }
- }
-
- private string GetLanguageProvider(ScriptRuntimeSetup setup) {
- var providerType = Provider;
- if (providerType != null) {
- return providerType.AssemblyQualifiedName;
- }
-
- if (Options.HasLanguageProvider) {
- return Options.LanguageProvider;
- }
-
- if (Options.RunFile != null) {
- string ext = Path.GetExtension(Options.RunFile);
- foreach (var lang in setup.LanguageSetups) {
- if (lang.FileExtensions.Any(e => DlrConfiguration.FileExtensionComparer.Equals(e, ext))) {
- return lang.TypeName;
- }
- }
- }
-
- throw new InvalidOptionException("No language specified.");
- }
-
- protected virtual CommandLine CreateCommandLine() {
- return new CommandLine();
- }
-
- protected virtual OptionsParser CreateOptionsParser() {
- return new OptionsParser<ConsoleOptions>();
- }
-
- protected virtual IConsole CreateConsole(ScriptEngine engine, CommandLine commandLine, ConsoleOptions options) {
- ContractUtils.RequiresNotNull(options, "options");
-
- if (options.TabCompletion) {
- return CreateSuperConsole(commandLine, options.ColorfulConsole);
- } else {
- return new BasicConsole(options.ColorfulConsole);
- }
- }
-
- // The advanced console functions are in a special non-inlined function so that
- // dependencies are pulled in only if necessary.
- [MethodImplAttribute(MethodImplOptions.NoInlining)]
- private static IConsole CreateSuperConsole(CommandLine commandLine, bool isColorful) {
- return new SuperConsole(commandLine, isColorful);
- }
-
- #endregion
-
- /// <summary>
- /// Request (from another thread) the console REPL loop to terminate
- /// </summary>
- /// <param name="exitCode">The caller can specify the exitCode corresponding to the event triggering
- /// the termination. This will be returned from CommandLine.Run</param>
- public virtual void Terminate(int exitCode) {
- _commandLine.Terminate(exitCode);
- }
-
- /// <summary>
- /// To be called from entry point.
- /// </summary>
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
- public virtual int Run(string[] args) {
-
- var runtimeSetup = CreateRuntimeSetup();
- var options = new ConsoleHostOptions();
- _optionsParser = new ConsoleHostOptionsParser(options, runtimeSetup);
-
- try {
- ParseHostOptions(args);
- } catch (InvalidOptionException e) {
- Console.Error.WriteLine("Invalid argument: " + e.Message);
- return _exitCode = 1;
- }
-
- SetEnvironment();
-
- string provider = GetLanguageProvider(runtimeSetup);
-
- LanguageSetup languageSetup = null;
- foreach (var language in runtimeSetup.LanguageSetups) {
- if (language.TypeName == provider) {
- languageSetup = language;
- }
- }
- if (languageSetup == null) {
- // the language doesn't have a setup -> create a default one:
- languageSetup = new LanguageSetup(Provider.AssemblyQualifiedName, Provider.Name);
- runtimeSetup.LanguageSetups.Add(languageSetup);
- }
-
- // inserts search paths for all languages (/paths option):
- InsertSearchPaths(runtimeSetup.Options, Options.SourceUnitSearchPaths);
-
- _languageOptionsParser = CreateOptionsParser();
-
- try {
- _languageOptionsParser.Parse(Options.IgnoredArgs.ToArray(), runtimeSetup, languageSetup, PlatformAdaptationLayer);
- } catch (InvalidOptionException e) {
- Console.Error.WriteLine(e.Message);
- return _exitCode = -1;
- }
-
- _runtime = new ScriptRuntime(runtimeSetup);
-
- try {
- _engine = _runtime.GetEngineByTypeName(provider);
- } catch (Exception e) {
- Console.Error.WriteLine(e.Message);
- return _exitCode = 1;
- }
-
- Execute();
- return _exitCode;
- }
-
- private static void InsertSearchPaths(IDictionary<string, object> options, ICollection<string> paths) {
- if (options != null && paths != null && paths.Count > 0) {
- var existingPaths = new List<string>(LanguageOptions.GetSearchPathsOption(options) ?? (IEnumerable<string>)ArrayUtils.EmptyStrings);
- existingPaths.InsertRange(0, paths);
- options["SearchPaths"] = existingPaths;
- }
- }
-
- #region Printing help
-
- protected virtual void PrintHelp() {
- Console.WriteLine(GetHelp());
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
- protected virtual string GetHelp() {
- StringBuilder sb = new StringBuilder();
-
- string[,] optionsHelp = Options.GetHelp();
-
- sb.AppendLine(String.Format("Usage: {0}.exe [<dlr-options>] [--] [<language-specific-command-line>]", ExeName));
- sb.AppendLine();
-
- sb.AppendLine("DLR options (both slash or dash could be used to prefix options):");
- ArrayUtils.PrintTable(sb, optionsHelp);
- sb.AppendLine();
-
- sb.AppendLine("Language specific command line:");
- PrintLanguageHelp(sb);
- sb.AppendLine();
-
- return sb.ToString();
- }
-
- public void PrintLanguageHelp(StringBuilder output) {
- ContractUtils.RequiresNotNull(output, "output");
-
- string commandLine, comments;
- string[,] options, environmentVariables;
-
- CreateOptionsParser().GetHelp(out commandLine, out options, out environmentVariables, out comments);
-
- // only display language specific options if one or more optinos exists.
- if (commandLine != null || options != null || environmentVariables != null || comments != null) {
- if (commandLine != null) {
- output.AppendLine(commandLine);
- output.AppendLine();
- }
-
- if (options != null) {
- output.AppendLine("Options:");
- ArrayUtils.PrintTable(output, options);
- output.AppendLine();
- }
-
- if (environmentVariables != null) {
- output.AppendLine("Environment variables:");
- ArrayUtils.PrintTable(output, environmentVariables);
- output.AppendLine();
- }
-
- if (comments != null) {
- output.Append(comments);
- output.AppendLine();
- }
-
- output.AppendLine();
- }
- }
-
- #endregion
-
- private void Execute() {
- #if !SILVERLIGHT
- if (_languageOptionsParser.CommonConsoleOptions.IsMta) {
- Thread thread = new Thread(ExecuteInternal);
- thread.SetApartmentState(ApartmentState.MTA);
- thread.Start();
- thread.Join();
- return;
- }
- #endif
- ExecuteInternal();
- }
-
- protected virtual void ExecuteInternal() {
- Debug.Assert(_engine != null);
-
- ConsoleOptions consoleOptions = _languageOptionsParser.CommonConsoleOptions;
-
- if (consoleOptions.PrintVersion){
- PrintVersion();
- }
-
- if (consoleOptions.PrintUsage){
- PrintUsage();
- }
-
- if (consoleOptions.Exit){
- _exitCode = 0;
- return;
- }
-
- switch (Options.RunAction) {
- case ConsoleHostOptions.Action.None:
- case ConsoleHostOptions.Action.RunConsole:
- _exitCode = RunCommandLine();
- break;
-
- case ConsoleHostOptions.Action.RunFile:
- _exitCode = RunFile();
- break;
-
- default:
- throw Assert.Unreachable;
- }
- }
-
- private void SetEnvironment() {
- Debug.Assert(Options.EnvironmentVars != null);
-
- #if !SILVERLIGHT
- foreach (string env in Options.EnvironmentVars) {
- if (!String.IsNullOrEmpty(env)) {
- string[] var_def = env.Split('=');
- System.Environment.SetEnvironmentVariable(var_def[0], (var_def.Length > 1) ? var_def[1] : "");
- }
- }
- #endif
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
- private int RunFile() {
- Debug.Assert(_engine != null);
-
- int result = 0;
- try {
- return _engine.CreateScriptSourceFromFile(Options.RunFile).ExecuteProgram();
- #if SILVERLIGHT
- } catch (ExitProcessException e) {
- result = e.ExitCode;
- #endif
- } catch (Exception e) {
- UnhandledException(Engine, e);
- result = 1;
- } finally {
- try {
- Snippets.SaveAndVerifyAssemblies();
- } catch (Exception) {
- result = 1;
- }
- }
-
- return result;
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
- private int RunCommandLine() {
- Debug.Assert(_engine != null);
-
- _commandLine = CreateCommandLine();
- ConsoleOptions consoleOptions = _languageOptionsParser.CommonConsoleOptions;
-
- if (_console == null) {
- _console = CreateConsole(Engine, _commandLine, consoleOptions);
- }
-
- int exitCode = 0;
- try {
- if (consoleOptions.HandleExceptions) {
- try {
- exitCode = _commandLine.Run(Engine, _console, consoleOptions);
- } catch (Exception e) {
- if (CommandLine.IsFatalException(e)) {
- // Some exceptions are too dangerous to try to catch
- throw;
- }
- UnhandledException(Engine, e);
- exitCode = 1;
- }
- } else {
- exitCode = _commandLine.Run(Engine, _console, consoleOptions);
- }
- } finally {
- try {
- Snippets.SaveAndVerifyAssemblies();
- } catch (Exception) {
- exitCode = 1;
- }
- }
-
- return exitCode;
- }
-
- private void PrintUsage()
- {
- StringBuilder sb = new StringBuilder();
- sb.AppendFormat("Usage: {0}.exe ", ExeName);
- PrintLanguageHelp(sb);
- Console.Write(sb.ToString());
- }
-
- protected void PrintVersion()
- {
- Console.WriteLine("{0} {1} on .NET {2}", Engine.Setup.DisplayName, Engine.LanguageVersion, typeof(String).Assembly.GetName().Version);
- }
-
- protected virtual void UnhandledException(ScriptEngine engine, Exception e) {
- Console.Error.Write("Unhandled exception");
- Console.Error.WriteLine(':');
-
- ExceptionOperations es = engine.GetService<ExceptionOperations>();
- Console.Error.WriteLine(es.FormatException(e));
- }
-
- protected static void PrintException(TextWriter output, Exception e) {
- Debug.Assert(output != null);
- ContractUtils.RequiresNotNull(e, "e");
-
- while (e != null) {
- output.WriteLine(e);
- e = e.InnerException;
- }
- }
- }
- }
-