Collection <string> BuiltInGlobbing(CmdletProvider provider, string path, ProviderRuntime runtime) { var containerProvider = CmdletProvider.As <ContainerCmdletProvider>(provider); var ciIntrinsics = new ChildItemCmdletProviderIntrinsics(_sessionState); // first we split the path into globbable components and put them on a stack to work with var componentStack = PathToStack(containerProvider, path, runtime); // we create a working list with partially globbed paths. each iteration will take all items from the // list and add the newly globbed part var workingPaths = new List <string>() { "" }; while (componentStack.Count > 0) { var partialPaths = new List <string>(workingPaths); workingPaths.Clear(); var globComp = componentStack.Pop(); // check if the current stack component has wildcards. If not, simply append it to all partialPaths // and add to workingPaths if (!WildcardPattern.ContainsWildcardCharacters(globComp)) { workingPaths.AddRange(from p in partialPaths select Path.Combine(containerProvider, p, globComp, runtime)); continue; } // otherwise get all childnames, check wildcard and combine the paths var globWC = new WildcardPattern(globComp, WildcardOptions.IgnoreCase); foreach (var partPath in partialPaths) { if (!containerProvider.ItemExists(partPath, runtime) || !containerProvider.HasChildItems(partPath, runtime)) { // TODO: throw an error if there was no globbing already performed (then the first part of // the path already did not exists as in a pattern like "/home/notExisting/*.txt" continue; } // TODO: verify if we should only consider matching containers or all. maybe the filter won't // apply to partial parts and we need to consider all var childNames = ciIntrinsics.GetValidChildNames(containerProvider, partPath, ReturnContainers.ReturnMatchingContainers, runtime); // TODO: check if Include/Exclude also match partial parts, but i guess only complete ones // add all combined path to the workingPaths for the next stack globbing iteration workingPaths.AddRange(from c in childNames where globWC.IsMatch(c) select Path.Combine(containerProvider, partPath, c, runtime)); } } // now filter the working paths by include/exlude. last flag is false or we wouldn't be globbing var filter = new IncludeExcludeFilter(runtime.Include, runtime.Exclude, false); var globbedPaths = from p in workingPaths where filter.Accepts(p) select p; return(new Collection <string>(globbedPaths.ToList())); }
internal Collection<string> GetGlobbedProviderPaths(string path, ProviderRuntime runtime, bool itemMustExist, out CmdletProvider provider) { var results = new Collection<string>(); ProviderInfo providerInfo; // get internal path, resolve home path and set provider info and drive info (if resolved) path = GetProviderSpecificPath(path, runtime, out providerInfo); provider = _sessionState.Provider.GetInstance(providerInfo); if (!ShouldGlob(path, runtime)) { // Although even ItemCmdletProvider supports ItemExists, PS doesn't seem // to throw errors when resolving paths with ItemProviders, only for ContainerProviders or higher // this behavior can be seen in the tests var containerProvider = provider as ContainerCmdletProvider; if (itemMustExist && containerProvider != null && !containerProvider.ItemExists(path, runtime)) { var msg = String.Format("An item with path {0} doesn't exist", path); runtime.WriteError(new ItemNotFoundException(msg).ErrorRecord); return results; } results.Add(path); return results; } if (providerInfo.Capabilities.HasFlag(ProviderCapabilities.ExpandWildcards)) { var filter = new IncludeExcludeFilter(runtime.Include, runtime.Exclude, runtime.IgnoreFiltersForGlobbing); foreach (var expanded in CmdletProvider.As<ItemCmdletProvider>(provider).ExpandPath(path, runtime)) { if (filter.Accepts(expanded)) { results.Add(expanded); } } } else { results = BuiltInGlobbing(provider, path, runtime); } return results; }
internal Collection <string> GetGlobbedProviderPaths(string path, ProviderRuntime runtime, bool itemMustExist, out CmdletProvider provider) { var results = new Collection <string>(); ProviderInfo providerInfo; // get internal path, resolve home path and set provider info and drive info (if resolved) path = GetProviderSpecificPath(path, runtime, out providerInfo); provider = _sessionState.Provider.GetInstance(providerInfo); if (!ShouldGlob(path, runtime)) { // Although even ItemCmdletProvider supports ItemExists, PS doesn't seem // to throw errors when resolving paths with ItemProviders, only for ContainerProviders or higher // this behavior can be seen in the tests var containerProvider = provider as ContainerCmdletProvider; if (itemMustExist && containerProvider != null && !containerProvider.ItemExists(path, runtime)) { var msg = String.Format("An item with path {0} doesn't exist", path); runtime.WriteError(new ItemNotFoundException(msg).ErrorRecord); return(results); } results.Add(path); return(results); } if (providerInfo.Capabilities.HasFlag(ProviderCapabilities.ExpandWildcards)) { var filter = new IncludeExcludeFilter(runtime.Include, runtime.Exclude, runtime.IgnoreFiltersForGlobbing); foreach (var expanded in CmdletProvider.As <ItemCmdletProvider>(provider).ExpandPath(path, runtime)) { if (filter.Accepts(expanded)) { results.Add(expanded); } } } else { results = BuiltInGlobbing(provider, path, runtime); } return(results); }
Collection<string> BuiltInGlobbing(CmdletProvider provider, string path, ProviderRuntime runtime) { var containerProvider = CmdletProvider.As<ContainerCmdletProvider>(provider); var ciIntrinsics = new ChildItemCmdletProviderIntrinsics(_sessionState); // first we split the path into globbable components and put them on a stack to work with var componentStack = PathToStack(containerProvider, path, runtime); // we create a working list with partially globbed paths. each iteration will take all items from the // list and add the newly globbed part var workingPaths = new List<string>() { "" }; while (componentStack.Count > 0) { var partialPaths = new List<string>(workingPaths); workingPaths.Clear(); var globComp = componentStack.Pop(); // check if the current stack component has wildcards. If not, simply append it to all partialPaths // and add to workingPaths if (!WildcardPattern.ContainsWildcardCharacters(globComp)) { workingPaths.AddRange(from p in partialPaths select Path.Combine(containerProvider, p, globComp, runtime)); continue; } // otherwise get all childnames, check wildcard and combine the paths var globWC = new WildcardPattern(globComp, WildcardOptions.IgnoreCase); foreach (var partPath in partialPaths) { if (!containerProvider.ItemExists(partPath, runtime) || !containerProvider.HasChildItems(partPath, runtime)) { // TODO: throw an error if there was no globbing already performed (then the first part of // the path already did not exists as in a pattern like "/home/notExisting/*.txt" continue; } // TODO: verify if we should only consider matching containers or all. maybe the filter won't // apply to partial parts and we need to consider all var childNames = ciIntrinsics.GetValidChildNames(containerProvider, partPath, ReturnContainers.ReturnMatchingContainers, runtime); // TODO: check if Include/Exclude also match partial parts, but i guess only complete ones // add all combined path to the workingPaths for the next stack globbing iteration workingPaths.AddRange(from c in childNames where globWC.IsMatch(c) select Path.Combine(containerProvider, partPath, c, runtime)); } } // now filter the working paths by include/exlude. last flag is false or we wouldn't be globbing var filter = new IncludeExcludeFilter(runtime.Include, runtime.Exclude, false); var globbedPaths = from p in workingPaths where filter.Accepts(p) select p; return new Collection<string>(globbedPaths.ToList()); }
// actual work with callid the providers internal void Get(string[] paths, bool recurse, ProviderRuntime runtime) { // the include/exclude filters apply to the results, not to the globbing process. Make this sure runtime.IgnoreFiltersForGlobbing = true; // globbing is here a little more complicated, so we do it "manually" (without GlobAndInvoke) foreach (var curPath in paths) { var path = curPath; // if the path won't be globbed or filtered, we will directly list it's child var listChildsWithoutRecursion = !Globber.ShouldGlob(path, runtime) && !runtime.HasFilters(); // the Path might be a mixture of a path and an include filter bool clearIncludeFilter; path = SplitFilterFromPath(path, recurse, runtime, out clearIncludeFilter); // now perform the actual globbing CmdletProvider provider; var globbed = Globber.GetGlobbedProviderPaths(path, runtime, out provider); var containerProvider = CmdletProvider.As<ContainerCmdletProvider>(provider); var filter = new IncludeExcludeFilter(runtime.Include, runtime.Exclude, false); foreach (var globPath in globbed) { try { // if we need to actively filter that stuff, we have to handle the recursion manually if (!filter.CanBeIgnored) { ManuallyGetChildItems(containerProvider, globPath, recurse, filter, runtime); return; } // otherwise just get the child items / the item directly if (recurse || listChildsWithoutRecursion) { GetItemOrChildItems(containerProvider, globPath, recurse, runtime); return; } // no recursion and globbing was performed: get the item, not the child items containerProvider.GetItem(globPath, runtime); } catch (Exception e) { HandleCmdletProviderInvocationException(e); } } // clean up the include filter of the runtime for the next item, if we split a filter from the path if (clearIncludeFilter) { runtime.Include.Clear(); } } }
private void ManuallyGetChildNames(ContainerCmdletProvider provider, string providerPath, string relativePath, ReturnContainers returnContainers, bool recurse, IncludeExcludeFilter filter, ProviderRuntime runtime) { // Affected by #trailingSeparatorAmbiguity // Sometimes, PS removes or appends a trailing slash to the providerPath // E.g. when the recurse == true, there is a trailing slash, but not when recurse == false. // As it calls the method with the slash being appended and not appended, PS doesn't seem to make // promises to the provider implementation whether or not the path has a trailing slash var childNames = GetValidChildNames(provider, providerPath, returnContainers, runtime); foreach (var childName in childNames) { // add the child only if the filter accepts it if (!filter.Accepts(childName)) { continue; } var path = Path.Combine(provider, relativePath, childName, runtime); runtime.WriteObject(path); } // check if we need to handle this recursively if (!recurse) { return; } // okay, we should use recursion, so get all child containers and call this function again childNames = GetValidChildNames(provider, providerPath, ReturnContainers.ReturnAllContainers, runtime); foreach (var childName in childNames) { var providerChildPath = Path.Combine(provider, providerPath, childName, runtime); if (Item.IsContainer(providerChildPath, runtime)) { // recursive call wirth child's provider path and relative path var relativeChildPath = Path.Combine(provider, relativePath, childName, runtime); ManuallyGetChildNames(provider, providerChildPath, relativeChildPath, returnContainers, true, filter, runtime); } } }
private void ManuallyGetChildItemsFromContainer(ContainerCmdletProvider provider, string path, bool recurse, IncludeExcludeFilter filter, ProviderRuntime runtime) { // we deal with a container: get all child items (all containers if we recurse) Dictionary<string, bool> matches = null; // When a provider specific filter is set, and we need to recurse, we need to check recurse into all // containers, but just get those that match the internal filter. Therefore we construct a lookup dict. // Looking up in a dictionary whether or not the itemis a match should be faster than using a list // If there is no filter, then ReturnAllContainers and ReturnMatchingContainers don't differ if (!String.IsNullOrEmpty(runtime.Filter)) { matches = GetValidChildNames(provider, path, ReturnContainers.ReturnMatchingContainers, runtime).ToDictionary(c => c, c => true); } var childNames = GetValidChildNames(provider, path, ReturnContainers.ReturnAllContainers, runtime); foreach (var childName in childNames) { var childPath = Path.Combine(provider, path, childName, runtime); // if the filter accepts the child (leaf or container) and it's potentially a filter match, get it if (filter.Accepts(childName) && (matches == null || matches.ContainsKey(childName))) { provider.GetItem(childPath, runtime); } // if we need to recurse and deal with a container, dive into it if (recurse && Item.IsContainer(childPath, runtime)) { ManuallyGetChildItemsFromContainer(provider, childPath, true, filter, runtime); } } }
private void ManuallyGetChildItems(ContainerCmdletProvider provider, string path, bool recurse, IncludeExcludeFilter filter, ProviderRuntime runtime) { // recursively get child names of containers or just the current child if the filter accepts it if (recurse && Item.IsContainer(path, runtime)) { ManuallyGetChildItemsFromContainer(provider, path, recurse, filter, runtime); return; } var childName = Path.ParseChildName(provider, path, runtime); if (filter.Accepts(childName)) { provider.GetItem(path, runtime); } }
internal void GetNames(string[] path, ReturnContainers returnContainers, bool recurse, ProviderRuntime runtime) { // the include/exclude filters apply to the results, not to the globbing process. Make this sure runtime.IgnoreFiltersForGlobbing = true; // compile here, not in every recursive iteration var filter = new IncludeExcludeFilter(runtime.Include, runtime.Exclude, false); // do the globbing manually, because the behavior depends on it... foreach (var p in path) { CmdletProvider provider; var doGlob = Globber.ShouldGlob(p, runtime); // even if we don't actually glob, the next method will return the resolved path & provider var resolved = Globber.GetGlobbedProviderPaths(p, runtime, out provider); var contProvider = CmdletProvider.As<ContainerCmdletProvider>(provider); foreach (var curPath in resolved) { if (!doGlob && filter.CanBeIgnored && !recurse) { contProvider.GetChildNames(curPath, returnContainers, runtime); continue; } if ((recurse || !doGlob) && Item.IsContainer(contProvider, curPath, runtime)) { ManuallyGetChildNames(contProvider, curPath, "", returnContainers, recurse, filter, runtime); continue; } var cn = Path.ParseChildName(contProvider, curPath, runtime); if (filter.Accepts(cn)) { runtime.WriteObject(cn); } } } }