Exemple #1
0
        internal static IEnumerable <FileSystemInfo> Traverse(DirectoryInfo root, Segment[] segments, int segmentIndex,
                                                              TraverseOptions options)
        {
            if (segmentIndex == segments.Length)
            {
                return(options.EmitDirectories
                    ? Enumerable.Repeat <FileSystemInfo>(root, 1)
                    : emptyFileSystemInfoArray);
            }

            var segment = segments[segmentIndex];

            switch (segment)
            {
            case DirectorySegment directorySegment:
            {
                var filesToEmit =
                    (options.EmitFiles && segmentIndex == segments.Length - 1)
                                ? options.GetFiles(root).Where(file => directorySegment.MatchesSegment(file.Name, options.CaseSensitive)).Cast <FileSystemInfo>()
                                : emptyFileSystemInfoArray;

                var dirSegmentItems = from directory in options.GetDirectories(root)
                                      where directorySegment.MatchesSegment(directory.Name, options.CaseSensitive)
                                      from item in Traverse(directory, segments, segmentIndex + 1, options)
                                      select item;

                return(filesToEmit.Concat(dirSegmentItems));
            }

            case DirectoryWildcard _:
            {
                var filesToEmit =
                    (options.EmitFiles && segmentIndex == segments.Length - 1)
                                ? options.GetFiles(root).Cast <FileSystemInfo>()
                                : emptyFileSystemInfoArray;

                // match zero path segments, consuming DirectoryWildcard
                var zeroMatch = Traverse(root, segments, segmentIndex + 1, options);

                // match consume 1 path segment but not the Wildcard
                var files = from directory in options.GetDirectories(root)
                            from item in Traverse(directory, segments, segmentIndex, options)
                            select item;

                return(filesToEmit.Concat(zeroMatch).Concat(files));
            }

            default:
                return(emptyFileSystemInfoArray);
            }
        }
        public IEnumerator <FileSystemInfo> GetEnumerator()
        {
            var roots     = new List <DirectoryInfo>();
            var rootCache = new List <DirectoryInfo>();

            roots.AddRange(_originalRoots);

            var segmentsLength   = _segments.Length;
            var nextSegmentRoots = new List <DirectoryInfo>();
            var segmentIndex     = 0;
            var emitDirectories  = _options.EmitDirectories;
            var emitFiles        = _options.EmitFiles;
            var cache            = new HashSet <string>();

            void Swap(ref List <DirectoryInfo> other)
            {
                var swap = roots;

                roots = other;
                other = swap;
            }

            while (true)
            {
                // no more segments. return all current roots
                var noMoreSegments = segmentIndex == segmentsLength;
                if (emitDirectories && noMoreSegments)
                {
                    foreach (var info in roots.Where(info => !cache.Contains(info.FullName)))
                    {
                        cache.Add(info.FullName);
                        yield return(info);
                    }
                }

                // no more roots or no more segments, go to next segment
                if (roots.Count == 0 || noMoreSegments)
                {
                    roots.Clear();
                    if (nextSegmentRoots.Count > 0)
                    {
                        Swap(ref nextSegmentRoots);
                        segmentIndex++;
                        continue;
                    }

                    yield break;
                }

                var segment       = _segments[segmentIndex];
                var onLastSegment = segmentIndex == segmentsLength - 1;
                if (emitFiles && onLastSegment)
                {
                    var allFiles = from job in roots
                                   let children = _options.GetFiles(job)
                                                  from file in FilesMatchingSegment(children, segment, _options.CaseSensitive)
                                                  select file;

                    foreach (var info in allFiles)
                    {
                        if (!cache.Contains(info.FullName))
                        {
                            cache.Add(info.FullName);
                            yield return(info);
                        }
                    }
                }
                rootCache.Clear();
                rootCache.AddRange(roots.SelectMany(job => JobsMatchingSegment(nextSegmentRoots, job, segment)));

                Swap(ref rootCache);
            }
        }