/// <summary> /// initialize contextual attributes and setup the context streams /// </summary> /// <param name="commandEvaluationContext">context</param> public void Initialize(CommandEvaluationContext commandEvaluationContext) { this.CommandEvaluationContext = commandEvaluationContext; // TODO: activate after DotNetConsole is no more static - see remarks below /* * Out = new ConsoleTextWriterWrapper(System.Console.Out); * Err = new TextWriterWrapper(System.Console.Error); * In = System.Console.In; */ var scriptOptions = ScriptOptions.Default; var abl = Assembly.GetExecutingAssembly(); scriptOptions = scriptOptions.WithReferences(abl); var cSharpScriptEngine = new CSharpScriptEngine(scriptOptions); //Out = DotNetConsole.Out; Out = new ShellConsoleTextWriterWrapper( commandEvaluationContext, System.Console.Out, cSharpScriptEngine ); /* * it can exists only one wrapper for out, * between the command evaluation context and dot net console */ DotNetConsole.Out = Out; Err = DotNetConsole.Err; In = DotNetConsole.In; commandEvaluationContext.SetStreams(Out, In, Err); }
public int ShellExec( CommandEvaluationContext context, string comPath, string args, string workingDirectory = null, bool waitForExit = true, bool isStreamsEchoEnabled = true, bool isOutputCaptureEnabled = true, bool mergeErrorStreamIntoOutput = true ) { return(ShellExec( context, comPath, args, workingDirectory, out _, waitForExit, isStreamsEchoEnabled, isOutputCaptureEnabled, mergeErrorStreamIntoOutput, false )); }
ExpressionEvaluationResult AnalysisPipelineParseResult( CommandEvaluationContext context, PipelineParseResult pipelineParseResult, string expr, int outputX, ParseResult parseResult ) { ExpressionEvaluationResult r = null; var errorText = ""; string[] t; int idx; string serr; switch (parseResult.ParseResultType) { case ParseResultType.Empty: r = new ExpressionEvaluationResult(expr, null, parseResult.ParseResultType, null, (int)ReturnCode.OK, null); break; case ParseResultType.NotValid: /* command syntax not valid */ var perComErrs = new Dictionary <string, List <CommandSyntaxParsingResult> >(); foreach (var prs in parseResult.SyntaxParsingResults) { if (prs.CommandSyntax != null) { if (perComErrs.TryGetValue(prs.CommandSyntax?.CommandSpecification?.Name, out var lst)) { lst.Add(prs); } else { perComErrs.Add(prs.CommandSyntax.CommandSpecification.Name, new List <CommandSyntaxParsingResult> { prs }); } } } var errs = new List <string>(); var minErrPosition = int.MaxValue; var errPositions = new List <int>(); foreach (var kvp in perComErrs) { var comSyntax = kvp.Value.First().CommandSyntax; foreach (var prs in kvp.Value) { foreach (var perr in prs.ParseErrors) { minErrPosition = Math.Min(minErrPosition, perr.Position); errPositions.Add(perr.Position); if (!errs.Contains(perr.Description)) { errs.Add(perr.Description); } } errorText += Br + Red + string.Join(Br + Red, errs); } errorText += $"{Br}{Red}for syntax: {comSyntax}{Br}"; } errPositions.Sort(); errPositions = errPositions.Distinct().ToList(); t = new string[expr.Length + 2]; for (int i = 0; i < t.Length; i++) { t[i] = " "; } foreach (var errPos in errPositions) { t[GetIndex(context, errPos, expr)] = Settings.ErrorPositionMarker + ""; } serr = string.Join("", t); Error(" ".PadLeft(outputX + 1) + serr, false, false); Error(errorText); r = new ExpressionEvaluationResult(expr, errorText, parseResult.ParseResultType, null, (int)ReturnCode.NotIdentified, null); break; case ParseResultType.Ambiguous: errorText += $"{Red}ambiguous syntaxes:{Br}"; foreach (var prs in parseResult.SyntaxParsingResults) { errorText += $"{Red}{prs.CommandSyntax}{Br}"; } Error(errorText); r = new ExpressionEvaluationResult(expr, errorText, parseResult.ParseResultType, null, (int)ReturnCode.NotIdentified, null); break; case ParseResultType.NotIdentified: t = new string[expr.Length + 2]; for (int j = 0; j < t.Length; j++) { t[j] = " "; } var err = parseResult.SyntaxParsingResults.First().ParseErrors.First(); idx = err.Position; t[idx] = Settings.ErrorPositionMarker + ""; errorText += Red + err.Description; serr = string.Join("", t); context.Errorln(" ".PadLeft(outputX) + serr); context.Errorln(errorText); r = new ExpressionEvaluationResult(expr, errorText, parseResult.ParseResultType, null, (int)ReturnCode.NotIdentified, null); break; case ParseResultType.SyntaxError: t = new string[expr.Length + 2]; for (int j = 0; j < t.Length; j++) { t[j] = " "; } var err2 = parseResult.SyntaxParsingResults.First().ParseErrors.First(); idx = err2.Index; t[idx] = Settings.ErrorPositionMarker + ""; errorText += Red + err2.Description; serr = string.Join("", t); context.Errorln(" ".PadLeft(outputX) + serr); context.Errorln(errorText); r = new ExpressionEvaluationResult(expr, errorText, parseResult.ParseResultType, null, (int)ReturnCode.NotIdentified, null); break; } return(r); }
/// <summary> /// exec a file with os shell exec or orbsh shell exec /// </summary> /// <param name="context">command evaluation context</param> /// <param name="comPath">command filePath</param> /// <param name="args">command line arguments string</param> /// <param name="output">shell exec result if any</param> /// <param name="waitForExit">true if wait for exec process exits</param> /// <param name="isStreamsEchoEnabled">if true, exec process output stream is echoized to context out (dump command output)</param> /// <param name="isOutputCaptureEnabled">if true capture the exec process output and give the result in parameter 'output'</param> /// <param name="mergeErrorStreamIntoOutput">if true merge exec process err stream content to the process output content (if process out capture is enabled)</param> /// <returns>exec process return code</returns> public int ShellExec( CommandEvaluationContext context, string comPath, string args, string workingDirectory, out string output, bool waitForExit = true, bool isStreamsEchoEnabled = true, bool isOutputCaptureEnabled = true, bool mergeErrorStreamIntoOutput = true, bool redirectStandardInput = false ) { Thread inputTask = null; TextReader stdin = null; ProcessWrapper pw = null; try { output = null; workingDirectory ??= Environment.CurrentDirectory; var processStartInfo = new ProcessStartInfo() { UseShellExecute = false, //StandardOutputEncoding = Encoding.UTF8, // keep system default //StandardErrorEncoding = Encoding.UTF8, // keep system default RedirectStandardError = true, RedirectStandardInput = redirectStandardInput, // allows access to process StandardInput RedirectStandardOutput = true, CreateNoWindow = true, FileName = comPath, Arguments = args, WindowStyle = ProcessWindowStyle.Normal, WorkingDirectory = workingDirectory }; var sb = new StringBuilder(); // batch shell exec ? if (Path.GetExtension(comPath) == context.ShellEnv.GetValue <string>(ShellEnvironmentVar.settings_clp_shellExecBatchExt)) { var batchMethod = typeof(CommandLineProcessorCommands).GetMethod(nameof(CommandLineProcessorCommands.Batch)); var r = Eval(context, batchMethod, "\"" + FileSystemPath.UnescapePathSeparators(comPath) + " " + args + "\"", 0); output = sb.ToString(); return(r.EvalResultCode); } // process exec pw = ProcessWrapper.ThreadRun( processStartInfo, null, (outStr) => { if (isStreamsEchoEnabled) { context.Out.Echoln(outStr); } if (isOutputCaptureEnabled) { sb.AppendLine(outStr); } }, (errStr) => { if (isStreamsEchoEnabled) { context.Errorln(errStr); } if (isOutputCaptureEnabled && mergeErrorStreamIntoOutput) { sb.AppendLine(errStr); } } ); if (context.ShellEnv.IsOptionSetted(ShellEnvironmentVar.settings_clp_enableShellExecTraceProcessStart)) { context.Out.Echoln($"{context.ShellEnv.Colors.TaskInformation}process '{Path.GetFileName(comPath)}' [{pw.Process.Id}] started(rdc)"); } int retCode = 0; int c = -1; if (waitForExit) { if (redirectStandardInput) { inputTask = new Thread( () => { try { var cp = comPath; stdin = System.Console.In; #if dbg Debug.WriteLine($"input task started [ cp = {cp} ]"); #endif while (!(bool)pw?.Process?.HasExited) { if (System.Console.KeyAvailable) { var key = System.Console.ReadKey(true); c = key.KeyChar; if (c > -1) { context.Out.ConsolePrint("" + (char)c); #if dbg Debug.Write((char)c); #endif pw?.Process.StandardInput.Write((char)c); pw?.Process.StandardInput.Flush(); } } Thread.Sleep(1); } #if dbg Debug.WriteLine("input task exited"); #endif } catch #if dbg (Exception ex) #endif { #if dbg Debug.WriteLine($"input task exited ({ex.Message})"); #endif } }); inputTask.Name = "forward input task"; inputTask.Start(); } var cancellationTask = Task.Run(() => { try { while (!(bool)pw?.Process?.HasExited) { if (IsCancellationRequested) { pw?.Process?.Kill(); } Thread.Sleep(1); } inputTask?.Interrupt(); #if dbg Debug.WriteLine($"cancellation task exited"); #endif } catch #if dbg (Exception ex) #endif { #if dbg Debug.WriteLine($"cancellation task exited ({ex.Message})"); #endif } }); pw.Process.WaitForExit(); retCode = pw.Process.ExitCode; pw.StdOutCallBackThread.Join(); pw.StdErrCallBackThread.Join(); output = sb.ToString(); } if (context.ShellEnv.IsOptionSetted(ShellEnvironmentVar.settings_clp_enableShellExecTraceProcessEnd)) { context.Out.Echoln($"{context.ShellEnv.Colors.TaskInformation}process '{Path.GetFileName(comPath)}' exited with code: {retCode}(rdc)"); } return(retCode); } catch (Exception shellExecException) { inputTask?.Interrupt(); throw new Exception($"ShellExec error: {shellExecException}", shellExecException); } finally { } }