internal static string TrimDrive(this string path, SHiPSDrive drive) { if (string.IsNullOrWhiteSpace(path) || drive == null) { return(path); } //Donot strip end slash here before the match. Otherwise, we cannot make match to work and 'dir' will show nothing. var path1 = path; //match our current drive style like JT:\\ or C:\foo.ps1:\\ wheren 'C:\foo.ps1' is a drive root? var match = drive.DriveTrimRegex.Match(path1); if (match.Success) { path1 = match.Groups[2].Value; } else { // match regular drive style like E:\ or JT:? // This is needed when cd MyProvider\MyProvider::JT:\A\B\C // cd .. to B; cd .. to A; and then cd tab, show A var match3 = SHiPSProvider.WellFormatPathRegex.Match(path1); if (match3.Success) { path1 = match3.Groups[2].Value; } } return(path1.TrimEnd('\\', '/')); }
private static IEnumerable <IPathNode> ProcessResultsWithCache( ICollection <object> results, IProviderContext context, SHiPSDirectory node, SHiPSDrive drive) { //TODO: async vs cache //we could yield result right away but we need to save the all children in the meantime because //InvokeScript can be costly.So we need to cache the results first by completing the foreach before //returning to a caller. List <IPathNode> retval = new List <IPathNode>(); //clear the child node list, get ready to get the refreshed ones node.Children?.Clear(); foreach (var result in results.WhereNotNull()) { // Making sure to obey the StopProcessing. if (context.Stopping) { return(null); } node.AddAsChildNode(result, drive, retval); } // Mark the node visited once we sucessfully fetched data. node.ItemNavigated = true; return(retval); }
/// <summary> /// Constructor for the content stream. /// </summary> /// <param name="context">A provider context.</param> /// <param name="drive">SHiPS based provider drive.</param> /// <param name="node">An object that is corresponding to the current node path.</param> public ContentWriter(IProviderContext context, SHiPSDrive drive, SHiPSBase node) { _drive = drive; _node = node; _context = context; _stream = new MemoryStream(); _writer = new StreamWriter(_stream); }
internal ContainerNodeService(SHiPSDrive drive, object container, SHiPSDirectory parent) { _drive = drive; _container = container as SHiPSDirectory; if (_container != null) { _container.Parent = parent; } }
internal LeafNodeService(object leafObject, SHiPSDrive drive, SHiPSDirectory parent) { _shipsLeaf = leafObject as SHiPSLeaf; _drive = drive; _contentHelper = new ContentHelper(_shipsLeaf, drive); if (_shipsLeaf != null) { _shipsLeaf.Parent = parent; } }
private static IEnumerable <IPathNode> ProcessResultsWithNoCache( ICollection <object> results, IProviderContext context, SHiPSDirectory node, SHiPSDrive drive) { foreach (var result in results.WhereNotNull()) { // Making sure to obey the StopProcessing. if (context.Stopping) { yield break; } var cnode = node.GetChildPNode(result, drive, false, cache: false); if (cnode != null) { yield return(cnode); } } }
internal static IPathNode ToPathNode(this object input, SHiPSDrive drive, SHiPSDirectory parent) { if (input == null) { return(null); } if (input is SHiPSDirectory) { return(new ContainerNodeService(drive, input, parent)); } if (input is SHiPSLeaf) { return(new LeafNodeService(input)); } // get or create a psobject on input var psobject = PSObject.AsPSObject(input); if (psobject == null) { return(null); } if (psobject.ImmediateBaseObject is SHiPSDirectory) { return(new ContainerNodeService(drive, psobject.ImmediateBaseObject, parent)); } if (psobject.ImmediateBaseObject is SHiPSLeaf) { return(new LeafNodeService(psobject.ImmediateBaseObject)); } return(new PSObjectNodeService(psobject)); }
/// <summary> /// Invokes a PowerShell script block; Removes the existing child node list before adding new ones. /// </summary> /// <param name="context">A ProviderContext object contains information that a PowerShell provider needs.</param> /// <param name="node">ContainerNode object that is corresponding to the current path.</param> /// <param name="drive">Current drive that a user is in use.</param> /// <param name="script">PowerShell script to be run.</param> /// <param name="errorHandler">Action for handling error cases.</param> /// <param name="args">Arguments passed into the script block.</param> /// <returns></returns> internal static IEnumerable <IPathNode> InvokeScriptBlockAndBuildTree( IProviderContext context, SHiPSDirectory node, SHiPSDrive drive, string script, Action <string, IProviderContext, IEnumerable <ErrorRecord> > errorHandler, params string[] args) { var progressId = 1; var activityId = Resource.RetrievingData; int percentComplete = 1; var desciption = (Resource.FetchingData).StringFormat(node.Name ?? ""); int waittime = 1000; // 1s CancellationTokenSource cts = new CancellationTokenSource(); var progressTracker = new ProgressTracker(progressId, activityId, desciption, node.BuiltinProgress); try { ICollection <object> results = new List <object>(); var errors = new ConcurrentBag <ErrorRecord>(); var parameters = context.GetSHiPSParameters(); var usingDynamicParameter = parameters.BoundParameters.UsingDynamicParameter(node, drive); //PowerShell engine hangs if we call like this in default runspace //var task = Task.Factory.StartNew(() => //{ // results = node.GetChildItem(); //}, cts.Token); var task = Task.Factory.StartNew(() => { results = CallPowerShellScript( node, drive.PowerShellInstance, parameters, script, output_DataAdded, (sender, e) => error_DataAdded(sender, e, errors), args); }, cts.Token); var stop = task.Wait(waittime, cts.Token); if (!stop && !cts.Token.IsCancellationRequested && !context.Stopping) { progressTracker.Start(context); } while (!stop && !cts.IsCancellationRequested && !context.Stopping) { stop = task.Wait(waittime, cts.Token); progressTracker.Update(++percentComplete, context); } progressTracker.End(context); if (errors.Count > 0) { // Cleanup child items only if the user type '-force'. if (context.Force) { //remove the cached child nodes for the failed node node.Children?.Clear(); //remove the node from its parent's children list so that it won't show again when a user types dir -force node.Parent?.Children.RemoveSafe(node.Name); } // report the error if there are any errorHandler?.Invoke(node.Name, context, errors); //do not yield break here as we need to display the rest of outputs } if (results == null || !results.Any()) { // Just because result is null, it does not mean that the call fails because the command may // return nothing. context.WriteDebug(Resource.InvokeScriptReturnNull.StringFormat(node.Name, context.Path)); if (errors.Count == 0) { // do not mark the node visited if there is an error. e.g., if login to azure fails, // we should not cache so that a user can dir again once the cred resolved. node.ItemNavigated = true; } //clear the child node list as the current node has null or empty children (results) if (context.Force) { node.Children?.Clear(); } return(Enumerable.Empty <IPathNode>()); } // Add the node list to the cache if needed return((node.UseCache && !usingDynamicParameter) ? ProcessResultsWithCache(results, context, node, drive, addNodeOnly: false) : ProcessResultsWithNoCache(results, context, node, drive)); } finally { if (!cts.IsCancellationRequested) { cts.Cancel(); } cts.Dispose(); progressTracker.End(context); // We complete the call. Reset the node parameters. node.SHiPSProviderContext.Clear(); //stop the running script drive.PowerShellInstance.Stop(); } }
/// <summary> /// Invokes a script block and updates the parent's children node list in the cached case. /// </summary> /// <param name="context">A ProviderContext object contains information that a PowerShell provider needs.</param> /// <param name="node">Node object that is corresponding to the current path.</param> /// <param name="drive">Current drive that a user is in use.</param> /// <param name="script">PowerShell script to be run.</param> /// <param name="errorHandler">Action for handling error cases.</param> /// <param name="args">Arguments passed into the script block.</param> /// <returns></returns> internal static ICollection <object> InvokeScriptBlock( IProviderContext context, SHiPSBase node, SHiPSDrive drive, string script, Action <string, IProviderContext, IEnumerable <ErrorRecord> > errorHandler, params string[] args) { try { var errors = new ConcurrentBag <ErrorRecord>(); var parameters = context?.GetSHiPSParameters(); var results = CallPowerShellScript( node, drive.PowerShellInstance, parameters, script, output_DataAdded, (sender, e) => error_DataAdded(sender, e, errors), args); if (errors.WhereNotNull().Any()) { if (context != null) { // report the error if there are any errorHandler?.Invoke(node.Name, context, errors); return(null); } else { // report the error if there are any var error = errors.FirstOrDefault(); var message = Environment.NewLine; message += error.ErrorDetails == null ? error.Exception.Message : error.ErrorDetails.Message; throw new InvalidDataException(message); } } if (results == null || !results.Any()) { return(null); } if (context != null && node.UseCache) { if (node.IsLeaf) { ProcessResultsWithCache(results, context, node.Parent, drive, addNodeOnly: true); } else { ProcessResultsWithCache(results, context, node as SHiPSDirectory, drive, addNodeOnly: true); } } return(results); } finally { //stop the running script drive.PowerShellInstance.Stop(); } }
internal static IPathNode GetChildPNode(this SHiPSDirectory parent, object child, SHiPSDrive drive, bool cache) { if (child == null || parent == null) { return(null); } var pNode = child.ToPathNode(drive, parent); if (pNode != null) { if (string.IsNullOrWhiteSpace(pNode.Name)) { //let the program continue by logging warning only because one bad node should not stop the navigation. drive.SHiPS.WriteWarning(Resources.Resource.NameWithNullOrEmpty.StringFormat(parent.Name)); // throw new InvalidDataException(Resources.Resource.NameWithNullOrEmpty.StringFormat(parent.Name)); return(null); } if (!cache) { return(pNode); } //warning if nodes have the same name because "directory" cannot be the same name var existNode = parent.Children.Get(pNode.Name); var first = existNode?.FirstOrDefault(); if (first != null && (first.GetNodeValue().IsCollection || (pNode is ContainerNodeService && !((ContainerNodeService)pNode).ContainerNode.IsLeaf))) { drive.SHiPS.WriteWarning( Resources.Resource.NodesWithSameName.StringFormat(parent.Name.EqualsIgnoreCase(drive.RootNode.Name) ? "root" : parent.Name, pNode.Name)); return(null); } return(pNode); } return(null); }
internal static IPathNode AddAsChildNode(this SHiPSDirectory parent, object child, SHiPSDrive drive, List <IPathNode> list) { var pNode = GetChildPNode(parent, child, drive, cache: true); if (pNode == null) { return(null); } //add to its child list parent.Children.GetOrCreateEntryIfDefault(pNode.Name, () => new List <IPathNode>()).Add(pNode); list.Add(pNode); return(pNode); }
internal static bool UsingDynamicParameter(this Dictionary <string, object> boundParameters, SHiPSDirectory node, SHiPSDrive drive) { if (node.SHiPSProviderContext.DynamicParameters == null) { return(false); } var usingDynamicParameter = false; var filter = false; if (boundParameters != null && boundParameters.Any()) { var defaultParameters = drive.GetChildItemDefaultParameters; usingDynamicParameter = boundParameters.Keys.Any(each => !defaultParameters.ContainsIgnoreCase(each)); object argument; if (!usingDynamicParameter && boundParameters.TryGetValue("Filter", out argument)) { filter = !string.IsNullOrWhiteSpace((string)argument); } } return(usingDynamicParameter || filter); }
internal static bool NeedRefresh(this IProviderContext context, SHiPSDirectory node, SHiPSDrive drive) { var myInvocationInfo = GetMyInvocationInfo(context.CmdletProvider); var verbose = false; var debug = false; var force = false; var usedDynamicParameter = false; if (myInvocationInfo == null) { return(false); } var boundParameters = myInvocationInfo.BoundParameters; if (boundParameters.Any()) { object argument; if (boundParameters.TryGetValue("Force", out argument)) { force = ((SwitchParameter)argument).IsPresent; } if (!force && boundParameters.TryGetValue("Verbose", out argument)) { verbose = ((SwitchParameter)argument).IsPresent; } if (!verbose && !force && boundParameters.TryGetValue("Debug", out argument)) { debug = ((SwitchParameter)argument).IsPresent; } if (!verbose && !force && !debug) { usedDynamicParameter = UsingDynamicParameter(boundParameters, node, drive); } } // If a user specify -force, -debug -verbose -filter or dynamic parameters, we do not use cache. return(force || debug || verbose || usedDynamicParameter); }
internal PathResolver(SHiPSProvider provider, SHiPSDrive driveInfo) { _provider = provider; _drive = driveInfo; }
internal ContentHelper(SHiPSBase node, SHiPSDrive drive) { _node = node; _drive = drive; }
internal ContainerNodeService(SHiPSDrive drive, object container) { _drive = drive; _container = container as SHiPSDirectory; }