/// <summary> /// Handles the tab key by calling all registered tab completion handlers. /// </summary> /// <param name="context">Context that can be used to inspect the current command line to perform tab completion</param> public void Handle(RichCommandLineContext context) { context.Intercept = true; context.RefreshTokenInfo(); try { foreach (var handler in TabCompletionHandlers) { if (handler.TryTabComplete(context)) { break; } } } catch (Exception ex) { if (ThrowOnTabCompletionHandlerException) { throw; } else { PowerLogger.LogLine("Tab completion handler threw exception: " + ex.ToString()); } } }
internal void Drain(bool block = true) { if (_stages.Count > 0) { _stages.First().Drain(); } while (block && IsDrained == false) { Thread.Sleep(10); } if (block) { PowerLogger.LogLine("The pipeline is drained"); lock (asyncExceptionLock) { try { if (asyncExceptions.Count == 1) { throw asyncExceptions.First(); } else if (asyncExceptions.Count > 1) { throw new AggregateException(asyncExceptions.ToArray()); } } finally { asyncExceptions.Clear(); } } } }
private void DoSyntaxHighlighting(RichCommandLineContext context) { if (Highlighter == null) { return; } bool highlightChanged = false; try { highlightChanged = Highlighter.TryHighlight(context); } catch (Exception ex) { if (ThrowOnSyntaxHighlightException) { throw; } else { PowerLogger.LogLine("Syntax highlighting threw exception: " + ex.ToString()); } } if (highlightChanged) { context.RefreshConsole(0, 0); } }
public void Double([ArgPipelineTarget(PipelineOnly = false)] double number) { var output = 2 * number; PowerLogger.LogLine("Double of " + number + " is " + output); Console.Write(number + " - I am the doubler, "); ConsoleString.WriteLine("Muahahahaha!", ConsoleColor.Green); ArgPipeline.Push(output); }
private static bool TryLoadAddInObject <TAttr, TBaseReq>(out TBaseReq result, params object[] constructorParams) { Type targetType = null; var powerArgsDir = Path.GetDirectoryName(typeof(Args).Assembly.Location); foreach (Assembly toInspect in GetSearchAssemblyCache()) { try { var match = (from t in toInspect.GetTypes() where t.HasAttr <TAttr>() && (t.GetInterfaces().Contains(typeof(TBaseReq)) || t.IsSubclassOf(typeof(TBaseReq))) select t).FirstOrDefault(); if (match != null) { targetType = match; break; } } catch (Exception ex) { PowerLogger.LogLine("Exception trying to reflect over an assembly to get type info: " + ex.ToString()); } } if (targetType == null) { PowerLogger.LogLine("Could not find an object with a base of " + typeof(TBaseReq).FullName + " that had attribute " + typeof(TAttr).FullName); result = default(TBaseReq); return(false); } try { result = (TBaseReq)Activator.CreateInstance(targetType, constructorParams); return(true); } catch (TargetInvocationException ex) { if (ex.InnerException == null) { throw; } if (ex.InnerException is ArgException) { throw ex.InnerException; } result = default(TBaseReq); return(false); } catch (Exception ex) { PowerLogger.LogLine("Could not initialize target type " + targetType.FullName + "\n\n" + ex.ToString()); result = default(TBaseReq); return(false); } }
/// <summary> /// This is the main hook point where the pipeline features get injected. This method is responsible for creating the pipeline if needed. It is also /// responsible for connecting to an external program if this program was launched by another program's pipeline manager. It is also responsible for /// supporting any pipeline stage actions (e.g. $filter) that are not supported if the [ArgPipeline] metadata is omitted from the root definition. /// </summary> /// <param name="context">The processing context</param> public override void BeforeParse(ArgHook.HookContext context) { ExternalPipelineInputStage externalStage; if (ExternalPipelineProvider.TryLoadInputStage(context.Definition, context.CmdLineArgs, out externalStage) && externalStage.IsProgramLaunchedByExternalPipeline) { externalStage.CommandLineDefinitionFactory = this.commandLineDeinitionFactory; while (externalStage.IsDrained == false) { Thread.Sleep(10); } PowerLogger.LogLine("Input stage drained"); context.CancelAllProcessing(); return; } else if (context.CmdLineArgs.Contains(PowerArgsPipeIndicator)) { ValidatePipeline(context); List <List <string> > stageCommandLines = new List <List <string> >(); stageCommandLines.Add(new List <string>()); for (int i = 0; i < context.CmdLineArgs.Length; i++) { var arg = context.CmdLineArgs[i]; if (arg == PowerArgsPipeIndicator) { stageCommandLines.Add(new List <string>()); } else { stageCommandLines.Last().Add(arg); } } context.CmdLineArgs = stageCommandLines.First().ToArray(); var manager = GetPipelineManagerFromContext(context); for (int i = 0; i < stageCommandLines.Count; i++) { var args = stageCommandLines[i]; if (args.Count == 0) { throw new ArgException("Missing action after pipeline indicator: " + PowerArgsPipeIndicator); } manager.CreateNextStage(context, args.ToArray(), this.commandLineDeinitionFactory); } context.CmdLineArgs = manager.Stages[0].CmdLineArgs.ToArray(); } else { // do nothing } }
public void Main() { object eval; if (PropertyName == "$item") { eval = FilterTarget; } else { var evalProp = FilterTarget.GetType().GetProperty(PropertyName); if (evalProp == null) { return; } if (evalProp.GetGetMethod() == null) { return; } eval = evalProp.GetValue(FilterTarget, null); if (eval == null) { return; } } if (eval is string == false && (Operator == FilterOperators.Contains || Operator == FilterOperators.NotContains)) { throw new ArgException("The Contains and NotContains operators can only be applied to properties of type string"); } object comparison = Value; try { if (eval.GetType() != typeof(string)) { if (ArgRevivers.CanRevive(eval.GetType())) { comparison = ArgRevivers.Revive(eval.GetType(), "", comparison + ""); } } } catch (Exception ex) { PowerLogger.LogLine("Unable to convert a string to:" + eval.GetType().FullName); return; } if (FilterLogic.FilterAcceptsObject(eval, Operator, comparison)) { ArgPipeline.Push(FilterTarget); } }
private void Dispatch(HttpListenerContext context) { try { var request = context.Request; using (var reader = new StreamReader(request.InputStream)) { var body = reader.ReadToEnd(); var message = JsonConvert.DeserializeObject <HttpPipelineMessage>(body); HttpPipelineControlResponse responseMessage = new HttpPipelineControlResponse(); if (MessageReceivedHandler != null) { try { responseMessage = MessageReceivedHandler(message); } catch (Exception ex) { PowerLogger.LogLine("Receive handler threw an exception"); responseMessage.ExceptionInfo = ex.ToString(); responseMessage.StatusCode = HttpStatusCode.BadRequest; } } var resposneMessageContents = JsonConvert.SerializeObject(responseMessage, HttpPipelineMessage.CommonSettings); using (var writer = new StreamWriter(context.Response.OutputStream)) { writer.Write(resposneMessageContents); } if (responseMessage.Close) { PowerLogger.LogLine("Closing listener because a response message told us to"); Stop(); } } } catch (Exception ex) { if (ListenException != null) { ListenException(ex); } else { throw; } } }
public void Stop() { if (listener.IsListening == false) { return; } listener.Stop(); PowerLogger.LogLine("Listener closed"); if (Stopped != null) { Stopped(); } }
/// <summary> /// The default implementation is to use the given definition factory to new up a definition and invoke an action using the given command line. You can /// override this if you want to process the given pipeline object in a different way. You will be called on this stage's processing thread and you should let exceptions /// flow through since they'll be bubbled up to the caller directly. /// </summary> /// <param name="o">An object recceived on the pipeline</param> protected virtual void OnObjectReceived(object o) { var definitionToUse = baseDefinition != null?CommandLineDefinitionFactory.MakeDefinition(baseDefinition) : CommandLineDefinitionFactory.MakeDefinition(); var childCommandLine = MapObject(o, definitionToUse); PowerLogger.LogLine("STAGE - " + StageIndex + " - Executing piped command: " + string.Join(" ", childCommandLine)); if (definitionToUse.Actions.Count > 0) { Args.InvokeAction(definitionToUse, childCommandLine); } else { Args.InvokeMain(definitionToUse, childCommandLine); } }
public object MapIncompatibleDirectTargets(Type desiredType, object incompatibleObject) { if (incompatibleObject is JObject == false) { throw new ArgumentException("Type not supported, must be JObject: " + incompatibleObject.GetType().FullName); } var revivedValue = Activator.CreateInstance(desiredType); int mappedProps = 0; foreach (JProperty prop in ((JObject)(incompatibleObject)).Properties()) { if (prop.Type == JTokenType.Object || prop.Type == JTokenType.Array || prop.Type == JTokenType.Bytes || prop.Type == JTokenType.Constructor || prop.Type == JTokenType.Comment) { continue; } var targetProp = desiredType.GetProperty(prop.Name); if (targetProp == null || targetProp.GetSetMethod() == null) { continue; } if (prop.Type == JTokenType.Null) { targetProp.SetValue(revivedValue, null, null); mappedProps++; } else if (ArgRevivers.CanRevive(targetProp.PropertyType)) { PowerLogger.LogLine("Mapped JObject property to " + desiredType.Name + "." + targetProp.Name); var revivedPropValue = ArgRevivers.Revive(targetProp.PropertyType, prop.Name, prop.Value.ToString()); targetProp.SetValue(revivedValue, revivedPropValue, null); mappedProps++; } } if (mappedProps == 0) { throw new ArgException("Could not map the given object to type: " + desiredType); } return(revivedValue); }
public override void Accept(object o) { PowerLogger.LogLine("Sending object over the wire: " + o); HttpPipelineControlResponse response = null; try { response = Sender.SendObject(o); } catch (WebException ex) { if (ex.Status == WebExceptionStatus.ConnectFailure) { try { throw new ArgException("Could not connect to external program '" + exe + "', possibly because it was not built with PowerArgs, or it does not have remote pipelining enabled. TODO - Help URL here.", ex); } catch (Exception toBubble) { this.Manager.BubbleAsyncException(toBubble); } } else { this.Manager.BubbleAsyncException(ex); } } catch (Exception ex) { this.Manager.BubbleAsyncException(ex); } if (response == null) { return; } if (response.StatusCode != HttpStatusCode.Accepted) { this.Manager.BubbleAsyncException(new ArgException("The external program '" + exe + "' could not accept the object of type: " + o.GetType().FullName + "\n\n" + response.ExceptionInfo)); } }
static void Main(string[] args) { PowerLogger.LogFile = @"C:\temp\ExternalLog-" + DateTime.Now.Ticks + ".log"; foreach (var arg in args) { if (arg == "PretendToNotBePowerArgsEnabled") { PowerLogger.LogLine("Pretended to not be PowerArgs enabled"); return; } } try { Args.InvokeAction <Program>(args); PowerLogger.LogLine("InvokeAction returned without error"); } catch (Exception ex) { PowerLogger.LogLine("Unhandled top level exception in test program\n\n" + ex.ToString()); } }
private void ProcessLoopImpl() { while (listener.IsListening) { try { var task = GetContextAsync(); try { task.Wait(); } catch (Exception) { if (listener.IsListening) { throw; } continue; } lastRequestReceivedTime = DateTime.Now; PowerLogger.LogLine("Listener accepted a request"); new Task(() => Dispatch(task.Result)).Start(); } catch (Exception ex) { if (ListenException != null) { ListenException(ex); } else { throw; } } } }
public HttpInputPipelineStage(CommandLineArgumentsDefinition baseDefinition, string[] rawCommandLine) : base(baseDefinition, CleanCommandLineOfInputPortInfo(rawCommandLine)) { int port; if (TryFindPort(rawCommandLine, out port) == false) { IsProgramLaunchedByExternalPipeline = false; return; } else { IsProgramLaunchedByExternalPipeline = true; } Init.InitIfNotAlreadyDone(); interceptor = ConsoleOutInterceptor.Instance; interceptor.Attach(); PowerLogger.LogLine("Initializing input pipe for command line on port " + port + ": " + string.Join(" ", this.CmdLineArgs)); wrappedStage = new InProcessPipelineStage(baseDefinition, this.CmdLineArgs.ToArray()); listener = new HttpPipelineMessageListener(port, TimeSpan.FromSeconds(10)); listener.Timeout += () => { PowerLogger.LogLine("HttpInputPipelineStage listener timed out."); Process.GetCurrentProcess().Kill(); }; wrappedStage.UnhandledException += (ex) => { QueueException(ex); }; listener.ListenException += (ex) => { QueueException(ex); }; listener.MessageReceivedHandler = (message) => { if (message.ControlAction == null) { LogLine("Pipe input received"); var pipedObject = DeserializePipedObject(message); wrappedStage.CommandLineDefinitionFactory = this.CommandLineDefinitionFactory; wrappedStage.Accept(pipedObject); LogLine("Pipe input processed"); return(new HttpPipelineControlResponse() { StatusCode = HttpStatusCode.Accepted }); } else if (message.ControlAction == "Drain") { Drain(); return(new HttpPipelineControlResponse() { StatusCode = HttpStatusCode.Accepted }); } else if (message.ControlAction == "Poll") { LogLine("Poll requested"); string pipedObjectArrayJson = null; string exceptionInfo = null; List <ConsoleCharacter> textOutput = null; lock (outputQueueLock) { List <object> batch = new List <object>(); while (outputQueue.Count > 0) { batch.Add(outputQueue.Dequeue()); } if (batch.Count > 0) { LogLine("Pipe output sent"); pipedObjectArrayJson = JsonConvert.SerializeObject(batch, HttpPipelineMessage.CommonSettings); } while (exceptionQueue.Count > 0) { LogLine("Exception output sent"); exceptionInfo = exceptionInfo ?? ""; exceptionInfo += exceptionQueue.Dequeue().ToString() + Environment.NewLine + Environment.NewLine; } var interceptedText = interceptor.ReadAndClear(); while (interceptedText.Count > 0) { textOutput = textOutput ?? new List <ConsoleCharacter>(); textOutput.Add(interceptedText.Dequeue()); } while (textOutputQueue.Count > 0) { textOutput = textOutput ?? new List <ConsoleCharacter>(); textOutput.Add(textOutputQueue.Dequeue()); } } return(new HttpPipelineControlResponse() { StatusCode = HttpStatusCode.OK, ExceptionInfo = exceptionInfo, ConsoleOutput = textOutput, PipedObjectArrayJson = pipedObjectArrayJson, Value = wrappedStage.IsDrained + "" }); } else if (message.ControlAction == "Close") { LogLine("Close requested"); ArgPipeline.ObjectExitedPipeline -= outputHandler; return(new HttpPipelineControlResponse() { StatusCode = HttpStatusCode.OK, Close = true }); } else { LogLine("Unrecognized action: " + message.ControlAction); return(new HttpPipelineControlResponse() { StatusCode = HttpStatusCode.BadRequest, ConsoleOutput = new ConsoleString("Unrecognized action: " + message.ControlAction).ToList() }); } }; outputHandler = (obj) => { LogLine("Pipe output queued"); lock (outputQueueLock) { outputQueue.Enqueue(obj); } }; ArgPipeline.ObjectExitedPipeline += outputHandler; listener.Start(); }
/// <summary> /// Reads a line of text from the console. Any interactions you've configured before calling this method will be in effect. /// </summary> /// <param name="initialBuffer">Optionally seed the prompt with an initial value that the end user can modify</param> /// <returns>a line of text from the console</returns> public ConsoleString ReadLine(ConsoleString initialBuffer = null) { RichCommandLineContext context; lock (SyncLock) { context = new RichCommandLineContext(this.HistoryManager); context.Console = this.Console; context.ConsoleStartTop = this.Console.CursorTop; context.ConsoleStartLeft = this.Console.CursorLeft; } if (initialBuffer != null) { lock (SyncLock) { context.ReplaceConsole(initialBuffer); } } while (true) { context.Reset(); context.KeyPressed = this.Console.ReadKey(true); lock (SyncLock) { context.CharacterToWrite = new ConsoleCharacter(context.KeyPressed.KeyChar); context.BufferPosition = this.Console.CursorLeft - context.ConsoleStartLeft + (this.Console.CursorTop - context.ConsoleStartTop) * this.Console.BufferWidth; if (context.BufferPosition < 0 || context.BufferPosition > context.Buffer.Count) { var message = string.Format("The cursor is not located within the bounds of the buffer. Cursor: {0},{1} Start position: {2},{3} Buffer position: {4} Buffer length: {5}", this.Console.CursorTop, this.Console.CursorLeft, context.ConsoleStartTop, context.ConsoleStartLeft, context.BufferPosition, context.Buffer.Count); try { throw new IndexOutOfRangeException(message); } catch (Exception ex) { PowerLogger.LogLine(ex.ToString()); throw; } } IKeyHandler handler = null; if (KeyHandlers.TryGetValue(context.KeyPressed.Key, out handler) == false && IsWriteable(context.KeyPressed)) { context.WriteCharacterForPressedKey(); DoSyntaxHighlighting(context); } else if (handler != null) { handler.Handle(context); if (context.Intercept == false && IsWriteable(context.KeyPressed)) { context.WriteCharacterForPressedKey(); } DoSyntaxHighlighting(context); if (context.IsFinished) { this.Console.WriteLine(); break; } } if (AfterReadKey != null) { AfterReadKey(context); } } } return(new ConsoleString(context.Buffer)); }
private string[] MapObject(object o, CommandLineArgumentsDefinition effectiveDefinition) { List <string> newCommandLine = new List <string>(); newCommandLine.AddRange(CmdLineArgs); var preParseResult = ArgParser.Parse(effectiveDefinition, newCommandLine.ToArray()); var predictedAction = effectiveDefinition.FindMatchingAction(this.CmdLineArgs[0]); if (predictedAction == null) { PowerLogger.LogLine("Could not determine action: " + this.CmdLineArgs[0] + " - Here are the supported action:"); foreach (var action in effectiveDefinition.Actions) { PowerLogger.LogLine(" " + action.DefaultAlias); } throw new ArgException("TODO - Could not determine action: " + this.CmdLineArgs[0]); } PowerLogger.LogLine("Predicted action is " + predictedAction.DefaultAlias); var argsToInspectForDirectMappingTarget = predictedAction.Arguments.Union(effectiveDefinition.Arguments).ToList(); var directMappingTarget = (from argument in argsToInspectForDirectMappingTarget where argument.Metadata.HasMeta <ArgPipelineTarget>() select argument).SingleOrDefault(); if (directMappingTarget != null) { var revivedValue = o; if (IsCompatible(o, directMappingTarget) == false) { PowerLogger.LogLine("Need to map " + o.GetType().FullName + " to " + directMappingTarget.ArgumentType.FullName); if (TrySimpleConvert(o, directMappingTarget.ArgumentType, out revivedValue)) { // we're good } else if (ArgPipelineObjectMapper.CurrentMapper == null) { throw new InvalidArgDefinitionException("Unable to attempt tp map type " + o.GetType().FullName + " to " + directMappingTarget.ArgumentType.FullName + " because no mapper is registered at ArgPipelineObjectMapperProvider.CurrentMapper"); } else { revivedValue = ArgPipelineObjectMapper.CurrentMapper.MapIncompatibleDirectTargets(directMappingTarget.ArgumentType, o); } } effectiveDefinition.Metadata.Add(new ArgumentOverrideHook(directMappingTarget, revivedValue)); } else { PowerLogger.LogLine("Attempting to shred object: " + o.ToString()); foreach (var argument in predictedAction.Arguments.Union(effectiveDefinition.Arguments)) { bool manualOverride = false; foreach (var explicitKey in preParseResult.ExplicitParameters.Keys) { if (argument.IsMatch(explicitKey)) { manualOverride = true; break; } } if (preParseResult.ImplicitParameters.ContainsKey(argument.Position)) { manualOverride = true; } if (manualOverride) { continue; } var mapper = argument.Metadata.Meta <ArgPipelineExtractor>() ?? new ArgPipelineExtractor(); string mappedKey, mappedValue; if (mapper.TryExtractObjectPropertyIntoCommandLineArgument(o, argument, out mappedKey, out mappedValue)) { newCommandLine.Add(mappedKey); newCommandLine.Add(mappedValue); } } } return(newCommandLine.ToArray()); }
private void LogLine(string s) { PowerLogger.LogLine(s); }