Determines whether a path matches a set of glob patterns.
コード例 #1
0
ファイル: RevisionAnalyzer.cs プロジェクト: pokke123/vss2git
        private void ProcessItem(VssItem item, string path, PathMatcher exclusionMatcher)
        {
            try
            {
                VssRevision previousRevision                = null;
                LinkedList <VssRevision>  revisions         = new LinkedList <VssRevision>();
                IEnumerable <VssRevision> originalRevisions = item.Revisions; // this is recreated from the file each time it is queried!!!
                foreach (VssRevision vssRevision in originalRevisions)
                {
                    if (previousRevision != null)
                    {
                        checkRevisionTime(item, previousRevision, vssRevision);
                    }
                    previousRevision = vssRevision;
                    revisions.AddLast(vssRevision);
                }
                foreach (VssRevision vssRevision in revisions)
                {
                    var actionType  = vssRevision.Action.Type;
                    var namedAction = vssRevision.Action as VssNamedAction;
                    if (namedAction != null)
                    {
                        if (actionType == VssActionType.Destroy)
                        {
                            // track destroyed files so missing history can be anticipated
                            // (note that Destroy actions on shared files simply delete
                            // that copy, so destroyed files can't be completely ignored)
                            destroyedFiles.Add(namedAction.Name.PhysicalName);
                        }

                        var targetPath = path + VssDatabase.ProjectSeparator + namedAction.Name.LogicalName;
                        if (exclusionMatcher != null && exclusionMatcher.Matches(targetPath))
                        {
                            // project action targets an excluded file
                            continue;
                        }
                    }

                    Revision revision = new Revision(vssRevision.DateTime,
                                                     vssRevision.User, item.ItemName, vssRevision.Version,
                                                     vssRevision.Comment, vssRevision.Action);

                    ICollection <Revision> revisionSet;
                    if (!sortedRevisions.TryGetValue(vssRevision.DateTime, out revisionSet))
                    {
                        revisionSet = new LinkedList <Revision>();
                        sortedRevisions[vssRevision.DateTime] = revisionSet;
                    }
                    revisionSet.Add(revision);
                    ++revisionCount;
                }
            }
            catch (RecordException e)
            {
                var message = string.Format("Failed to read revisions for {0} ({1}): {2}",
                                            path, item.PhysicalName, ExceptionFormatter.Format(e));
                LogException(e, message);
                ReportError(message);
            }
        }
コード例 #2
0
ファイル: ProjectAnalyzer.cs プロジェクト: markjforte/vss2git
        public void AnalyzeProject()
        {
            PathMatcher exclusionMatcher = null;

            if (!string.IsNullOrEmpty(excludeFiles))
            {
                var excludeFileArray = excludeFiles.Split(
                    new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                exclusionMatcher = new PathMatcher(excludeFileArray);
            }

            workQueue.AddLast(delegate(object work)
            {
                logger.WriteSectionSeparator();
                LogStatus(work, "Building active project list");

                logger.WriteLine("Root project: {0}", vssRootProject.Path);
                logger.WriteLine("Excluded files: {0}", excludeFiles);

                int excludedProjects = 0;
                var stopwatch        = Stopwatch.StartNew();
                VssUtil.RecurseItems(vssRootProject,
                                     delegate(VssProject subproject)
                {
                    if (workQueue.IsAborting)
                    {
                        return(RecursionStatus.Abort);
                    }

                    var path = subproject.Path;
                    if (exclusionMatcher != null && exclusionMatcher.Matches(path))
                    {
                        logger.WriteLine("Excluding project {0}", path);
                        ++excludedProjects;
                        return(RecursionStatus.Skip);
                    }

                    if (!deletedProjects.Contains(subproject.PhysicalName))
                    {
                        ProcessProject(subproject, path, exclusionMatcher);
                        ++projectCount;
                    }

                    return(RecursionStatus.Continue);
                },
                                     delegate(VssProject subproject, VssFile file)
                {
                    if (workQueue.IsAborting)
                    {
                        return(RecursionStatus.Abort);
                    }
                    return(RecursionStatus.Continue);
                });
                stopwatch.Stop();

                logger.WriteSectionSeparator();
                logger.WriteLine("Analysis complete in {0:HH:mm:ss}", new DateTime(stopwatch.ElapsedTicks));
                logger.WriteLine("Projects: {0} ({1} excluded)", projectCount, excludedProjects);
            });
        }
コード例 #3
0
ファイル: ProjectAnalyzer.cs プロジェクト: markjforte/vss2git
        public void AnalyzeProject()
        {
            PathMatcher exclusionMatcher = null;
            if (!string.IsNullOrEmpty(excludeFiles))
            {
                var excludeFileArray = excludeFiles.Split(
                    new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                exclusionMatcher = new PathMatcher(excludeFileArray);
            }

            workQueue.AddLast(delegate(object work)
            {
                logger.WriteSectionSeparator();
                LogStatus(work, "Building active project list");

                logger.WriteLine("Root project: {0}", vssRootProject.Path);
                logger.WriteLine("Excluded files: {0}", excludeFiles);

                int excludedProjects = 0;
                var stopwatch = Stopwatch.StartNew();
                VssUtil.RecurseItems(vssRootProject,
                    delegate(VssProject subproject)
                    {
                        if (workQueue.IsAborting)
                        {
                            return RecursionStatus.Abort;
                        }

                        var path = subproject.Path;
                        if (exclusionMatcher != null && exclusionMatcher.Matches(path))
                        {
                            logger.WriteLine("Excluding project {0}", path);
                            ++excludedProjects;
                            return RecursionStatus.Skip;
                        }

                        if (!deletedProjects.Contains(subproject.PhysicalName))
                        {
                            ProcessProject(subproject, path, exclusionMatcher);
                            ++projectCount;
                        }

                        return RecursionStatus.Continue;
                    },
                    delegate(VssProject subproject, VssFile file)
                    {
                        if (workQueue.IsAborting)
                        {
                            return RecursionStatus.Abort;
                        }
                        return RecursionStatus.Continue;
                    });
                stopwatch.Stop();

                logger.WriteSectionSeparator();
                logger.WriteLine("Analysis complete in {0:HH:mm:ss}", new DateTime(stopwatch.ElapsedTicks));
                logger.WriteLine("Projects: {0} ({1} excluded)", projectCount, excludedProjects);
            });
        }
コード例 #4
0
        private void ProcessItem(VssItem item, string path, PathMatcher exclusionMatcher)
        {
            try
            {
                foreach (var vssRevision in item.Revisions)
                {
                    var actionType = vssRevision.Action.Type;
                    if (vssRevision.Action is VssNamedAction namedAction)
                    {
                        if (actionType == VssActionType.Destroy)
                        {
                            // track destroyed files so missing history can be anticipated
                            // (note that Destroy actions on shared files simply delete
                            // that copy, so destroyed files can't be completely ignored)
                            DestroyedFiles.Add(namedAction.Name.PhysicalName);
                        }

                        var targetPath = path + VssDatabase.ProjectSeparator + namedAction.Name.LogicalName;
                        if (exclusionMatcher != null && exclusionMatcher.Matches(targetPath))
                        {
                            // project action targets an excluded file
                            continue;
                        }
                    }

                    var revision = new Revision(vssRevision.DateTime,
                                                vssRevision.User, item.ItemName, vssRevision.Version,
                                                vssRevision.Comment, vssRevision.Action);

                    ICollection <Revision> revisionSet;
                    if (!SortedRevisions.TryGetValue(vssRevision.DateTime, out revisionSet))
                    {
                        revisionSet = new LinkedList <Revision>();
                        SortedRevisions[vssRevision.DateTime] = revisionSet;
                    }
                    revisionSet.Add(revision);
                    ++revisionCount;
                }
            }
            catch (RecordException e)
            {
                var message = string.Format("Failed to read revisions for {0} ({1}): {2}",
                                            path, item.PhysicalName, ExceptionFormatter.Format(e));
                LogException(e, message);
                ReportError(message);
            }
        }
コード例 #5
0
ファイル: ProjectAnalyzer.cs プロジェクト: markjforte/vss2git
        private void ProcessProject(VssProject project, string path, PathMatcher exclusionMatcher)
        {
            try
            {
                ProjectLocation projectLocation;
                if (sortedProjectLocations.TryGetValue(project.PhysicalName, out projectLocation))
                {
                    logger.WriteLine("Unexpected: ProjectAnalyzer.ProcessProject: sortedProjectLocations already contains project: {0}", project.PhysicalName);
                }
                else
                {
                    projectLocation = new ProjectLocation(project.PhysicalName, path);
                    sortedProjectLocations[project.PhysicalName] = projectLocation;
                };

                foreach (VssRevision vssRevision in project.Revisions)
                {
                    var actionType  = vssRevision.Action.Type;
                    var namedAction = vssRevision.Action as VssNamedAction;
                    if (namedAction != null)
                    {
                        var targetPath = path + VssDatabase.ProjectSeparator + namedAction.Name.LogicalName;
                        if (exclusionMatcher != null && exclusionMatcher.Matches(targetPath))
                        {
                            // project action targets an excluded file
                            continue;
                        }

                        if (namedAction.Name.IsProject)
                        {
                            if (
                                (actionType == VssActionType.Delete) ||
                                (actionType == VssActionType.Destroy)
                                )
                            {
                                deletedProjects.Add(namedAction.Name.PhysicalName);
                            }
                            else if (
                                (actionType == VssActionType.Recover) ||
                                (actionType == VssActionType.Share)
                                )
                            {
                                deletedProjects.Remove(namedAction.Name.PhysicalName);
                            }
                        }
                        else
                        {
                            if (
                                (actionType == VssActionType.Delete) ||
                                (actionType == VssActionType.Destroy)
                                )
                            {
                                projectLocation.DeletedFiles.Add(namedAction.Name.PhysicalName);
                            }
                            else if (
                                (actionType == VssActionType.Recover) ||
                                (actionType == VssActionType.Share)
                                )
                            {
                                projectLocation.DeletedFiles.Remove(namedAction.Name.PhysicalName);
                            }
                        }
                    }
                }
            }
            catch (RecordException e)
            {
                var message = string.Format("ProjectAnalyzer.ProcessProject: Failed to process project for {0} ({1}): {2}",
                                            path, project.PhysicalName, ExceptionFormatter.Format(e));
                LogException(e, message);
                ReportError(message);
            }
        }
コード例 #6
0
ファイル: RevisionAnalyzer.cs プロジェクト: rustyx/vss2git
        private void ProcessItem(VssItem item, string path, PathMatcher exclusionMatcher)
        {
            try
            {
                VssRevision previousRevision = null;
                LinkedList<VssRevision> revisions = new LinkedList<VssRevision>();
                IEnumerable<VssRevision> originalRevisions = item.Revisions; // this is recreated from the file each time it is queried!!!
                foreach (VssRevision vssRevision in originalRevisions)
                {
                    if (previousRevision != null)
                    {
                        checkRevisionTime(item, previousRevision, vssRevision);
                    }
                    previousRevision = vssRevision;
                    revisions.AddLast(vssRevision);
                }
                foreach (VssRevision vssRevision in revisions)
                {
                    var actionType = vssRevision.Action.Type;
                    var namedAction = vssRevision.Action as VssNamedAction;
                    if (namedAction != null)
                    {
                        if (actionType == VssActionType.Destroy)
                        {
                            // track destroyed files so missing history can be anticipated
                            // (note that Destroy actions on shared files simply delete
                            // that copy, so destroyed files can't be completely ignored)
                            destroyedFiles.Add(namedAction.Name.PhysicalName);
                        }

                        var targetPath = path + VssDatabase.ProjectSeparator + namedAction.Name.LogicalName;
                        if (exclusionMatcher != null && exclusionMatcher.Matches(targetPath))
                        {
                            // project action targets an excluded file
                            continue;
                        }
                    }

                    Revision revision = new Revision(vssRevision.DateTime,
                        vssRevision.User, item.ItemName, vssRevision.Version,
                        vssRevision.Comment, vssRevision.Action);

                    ICollection<Revision> revisionSet;
                    if (!sortedRevisions.TryGetValue(vssRevision.DateTime, out revisionSet))
                    {
                        revisionSet = new LinkedList<Revision>();
                        sortedRevisions[vssRevision.DateTime] = revisionSet;
                    }
                    revisionSet.Add(revision);
                    ++revisionCount;
                }
            }
            catch (RecordException e)
            {
                var message = string.Format("Failed to read revisions for {0} ({1}): {2}",
                    path, item.PhysicalName, ExceptionFormatter.Format(e));
                LogException(e, message);
                ReportError(message);
            }
        }
コード例 #7
0
ファイル: RevisionAnalyzer.cs プロジェクト: rustyx/vss2git
        public void AddItem(VssProject project)
        {
            if (project == null)
            {
                throw new ArgumentNullException("project");
            }
            else if (project.Database != database)
            {
                throw new ArgumentException("Project database mismatch", "project");
            }

            if (timeFixList == null)
            {
                // load the time fix list only once
                timeFixList = ReadTimeFixList(database.BasePath, "time-fix-list.txt");
            }

            rootProjects.AddLast(project);

            PathMatcher exclusionMatcher = null;
            if (!string.IsNullOrEmpty(excludeFiles))
            {
                var excludeFileArray = excludeFiles.Split(
                    new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                exclusionMatcher = new PathMatcher(excludeFileArray);
            }

            workQueue.AddLast(delegate(object work)
            {
                logger.WriteSectionSeparator();
                LogStatus(work, "Building revision list");

                logger.WriteLine("Root project: {0}", project.Path);
                logger.WriteLine("Excluded files: {0}", excludeFiles);

                int excludedProjects = 0;
                int excludedFiles = 0;
                var stopwatch = Stopwatch.StartNew();
                VssUtil.RecurseItems(project,
                    delegate(VssProject subproject)
                    {
                        if (workQueue.IsAborting)
                        {
                            return RecursionStatus.Abort;
                        }

                        var path = subproject.Path;
                        if (exclusionMatcher != null && exclusionMatcher.Matches(path))
                        {
                            logger.WriteLine("Excluding project {0}", path);
                            ++excludedProjects;
                            return RecursionStatus.Skip;
                        }

                        ProcessItem(subproject, path, exclusionMatcher);
                        ++projectCount;
                        return RecursionStatus.Continue;
                    },
                    delegate(VssProject subproject, VssFile file)
                    {
                        if (workQueue.IsAborting)
                        {
                            return RecursionStatus.Abort;
                        }

                        var path = file.GetPath(subproject);
                        if (exclusionMatcher != null && exclusionMatcher.Matches(path))
                        {
                            logger.WriteLine("Excluding file {0}", path);
                            ++excludedFiles;
                            return RecursionStatus.Skip;
                        }

                        // only process shared files once (projects are never shared)
                        if (!processedFiles.Contains(file.PhysicalName))
                        {
                            processedFiles.Add(file.PhysicalName);
                            ProcessItem(file, path, exclusionMatcher);
                            ++fileCount;
                        }
                        return RecursionStatus.Continue;
                    });
                stopwatch.Stop();

                logger.WriteSectionSeparator();
                logger.WriteLine("Analysis complete in {0:HH:mm:ss}", new DateTime(stopwatch.ElapsedTicks));
                logger.WriteLine("Projects: {0} ({1} excluded)", projectCount, excludedProjects);
                logger.WriteLine("Files: {0} ({1} excluded)", fileCount, excludedFiles);
                logger.WriteLine("Revisions: {0}", revisionCount);
            });
        }
コード例 #8
0
ファイル: ProjectAnalyzer.cs プロジェクト: markjforte/vss2git
        private void ProcessProject(VssProject project, string path, PathMatcher exclusionMatcher)
        {
            try
            {
                ProjectLocation projectLocation;
                if (sortedProjectLocations.TryGetValue(project.PhysicalName, out projectLocation))
                    logger.WriteLine("Unexpected: ProjectAnalyzer.ProcessProject: sortedProjectLocations already contains project: {0}", project.PhysicalName);
                else
                {
                    projectLocation = new ProjectLocation(project.PhysicalName, path);
                    sortedProjectLocations[project.PhysicalName] = projectLocation;
                };

                foreach (VssRevision vssRevision in project.Revisions)
                {
                    var actionType = vssRevision.Action.Type;
                    var namedAction = vssRevision.Action as VssNamedAction;
                    if (namedAction != null)
                    {
                        var targetPath = path + VssDatabase.ProjectSeparator + namedAction.Name.LogicalName;
                        if (exclusionMatcher != null && exclusionMatcher.Matches(targetPath))
                        {
                            // project action targets an excluded file
                            continue;
                        }

                        if (namedAction.Name.IsProject)
                        {
                            if (
                                (actionType == VssActionType.Delete) ||
                                (actionType == VssActionType.Destroy)
                            )
                                deletedProjects.Add(namedAction.Name.PhysicalName);
                            else if (
                                (actionType == VssActionType.Recover) ||
                                (actionType == VssActionType.Share)
                            )
                                deletedProjects.Remove(namedAction.Name.PhysicalName);
                        }
                        else
                        {
                            if (
                                (actionType == VssActionType.Delete) ||
                                (actionType == VssActionType.Destroy)
                            )
                                projectLocation.DeletedFiles.Add(namedAction.Name.PhysicalName);
                            else if (
                                (actionType == VssActionType.Recover) ||
                                (actionType == VssActionType.Share)
                            )
                                projectLocation.DeletedFiles.Remove(namedAction.Name.PhysicalName);
                        }

                    }
                }
            }
            catch (RecordException e)
            {
                var message = string.Format("ProjectAnalyzer.ProcessProject: Failed to process project for {0} ({1}): {2}",
                    path, project.PhysicalName, ExceptionFormatter.Format(e));
                LogException(e, message);
                ReportError(message);
            }
        }
コード例 #9
0
ファイル: RevisionAnalyzer.cs プロジェクト: xewelus/vss2git
        public void AddItem(VssProject project)
        {
            if (project == null)
            {
                throw new ArgumentNullException("project");
            }
            else if (project.Database != database)
            {
                throw new ArgumentException("Project database mismatch", "project");
            }

            rootProjects.AddLast(project);

            PathMatcher exclusionMatcher = null;

            if (!string.IsNullOrEmpty(excludeFiles))
            {
                var excludeFileArray = excludeFiles.Split(
                    new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                exclusionMatcher = new PathMatcher(excludeFileArray);
            }

            workQueue.AddLast(delegate(object work)
            {
                logger.WriteSectionSeparator();
                LogStatus(work, "Building revision list");

                logger.WriteLine("Root project: {0}", project.Path);
                logger.WriteLine("Excluded files: {0}", excludeFiles);

                int excludedProjects = 0;
                int excludedFiles    = 0;
                var stopwatch        = Stopwatch.StartNew();
                VssUtil.RecurseItems(project,
                                     delegate(VssProject subproject)
                {
                    if (workQueue.IsAborting)
                    {
                        return(RecursionStatus.Abort);
                    }

                    var path = subproject.Path;
                    if (exclusionMatcher != null && exclusionMatcher.Matches(path))
                    {
                        logger.WriteLine("Excluding project {0}", path);
                        ++excludedProjects;
                        return(RecursionStatus.Skip);
                    }

                    ProcessItem(subproject, path, exclusionMatcher);
                    ++projectCount;
                    return(RecursionStatus.Continue);
                },
                                     delegate(VssProject subproject, VssFile file)
                {
                    if (workQueue.IsAborting)
                    {
                        return(RecursionStatus.Abort);
                    }

                    var path = file.GetPath(subproject);
                    if (exclusionMatcher != null && exclusionMatcher.Matches(path))
                    {
                        logger.WriteLine("Excluding file {0}", path);
                        ++excludedFiles;
                        return(RecursionStatus.Skip);
                    }

                    // only process shared files once (projects are never shared)
                    if (!processedFiles.Contains(file.PhysicalName))
                    {
                        processedFiles.Add(file.PhysicalName);
                        ProcessItem(file, path, exclusionMatcher);
                        ++fileCount;
                    }
                    return(RecursionStatus.Continue);
                });
                stopwatch.Stop();

                logger.WriteSectionSeparator();
                logger.WriteLine("Analysis complete in {0:HH:mm:ss}", new DateTime(stopwatch.ElapsedTicks));
                logger.WriteLine("Projects: {0} ({1} excluded)", projectCount, excludedProjects);
                logger.WriteLine("Files: {0} ({1} excluded)", fileCount, excludedFiles);
                logger.WriteLine("Revisions: {0}", revisionCount);
            });
        }
コード例 #10
0
ファイル: FileAnalyzer.cs プロジェクト: markjforte/vss2git
        public void AddItem(VssProject project)
        {
            if (project == null)
            {
                throw new ArgumentNullException("project");
            }

            PathMatcher exclusionMatcher = null;
            if (!string.IsNullOrEmpty(excludeFiles))
            {
                var excludeFileArray = excludeFiles.Split(
                    new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                exclusionMatcher = new PathMatcher(excludeFileArray);
            }

            workQueue.AddLast(delegate(object work)
            {
                logger.WriteSectionSeparator();
                LogStatus(work, "Building file location dictionary");

                logger.WriteLine("Root project: {0}", project.Path);
                logger.WriteLine("Excluded files: {0}", excludeFiles);

                int excludedFiles = 0;
                var stopwatch = Stopwatch.StartNew();
                VssUtil.RecurseItems(project,
                    delegate(VssProject subproject)
                    {
                        if (workQueue.IsAborting)
                        {
                            return RecursionStatus.Abort;
                        }
                        return RecursionStatus.Continue;
                    },
                    delegate(VssProject subproject, VssFile file)
                    {
                        if (workQueue.IsAborting)
                        {
                            return RecursionStatus.Abort;
                        }

                        var path = file.GetPath(subproject);
                        if (exclusionMatcher != null && exclusionMatcher.Matches(path))
                        {
                            logger.WriteLine("Excluding file {0}", path);
                            ++excludedFiles;
                            return RecursionStatus.Skip;
                        }

                        // Don't process files in deleted projects
                        if (!projectAnalyzer.DeletedProjects.Contains(subproject.PhysicalName))
                        {
                            ProjectLocation projectLocation;
                            if (!projectAnalyzer.SortedProjectLocations.TryGetValue(subproject.PhysicalName, out projectLocation))
                            {
                                // If the project is not found it is (i.e. should) be due to exclusionMatcher
                                //logger.WriteLine("Unexpected: FileAnalyzer: SortedProjectLocations does not contain project: {0}", subproject.PhysicalName);
                            }
                            else if (!projectLocation.DeletedFiles.Contains(file.PhysicalName))
                            {
                                // If the file is shared it might be in more than one project...
                                // But this should not happen using this alternate import method!
                                if (processedFiles.Contains(file.PhysicalName))
                                {
                                    ++sharedFileCount;
                                    logger.WriteLine("Unexpected: FileAnalyzer: File shared in more tha one project: {0}: {1}", file.PhysicalName, subproject.Path);
                                }
                                else
                                {
                                    processedFiles.Add(file.PhysicalName);
                                    FileLocation fileLocation;
                                    if (sortedFileLocations.TryGetValue(file.PhysicalName, out fileLocation))
                                        logger.WriteLine("Unexpected: FileAnalyzer: sortedFileLocations already contains file: {0}", file.PhysicalName);
                                    else
                                    {
                                        fileLocation = new FileLocation(file.PhysicalName, file.GetPath(subproject));
                                        sortedFileLocations[file.PhysicalName] = fileLocation;
                                    }
                                    ++fileCount;
                                }
                            }
                        }

                        return RecursionStatus.Continue;
                    });
                stopwatch.Stop();

                logger.WriteSectionSeparator();
                logger.WriteLine("Analysis complete in {0:HH:mm:ss}", new DateTime(stopwatch.ElapsedTicks));
                logger.WriteLine("Files: {0} ({1} excluded)", fileCount, excludedFiles);
                logger.WriteLine("Shared Files: {0}", sharedFileCount);

                if (sharedFileCount > 0)
                {
                    workQueue.Abort();
                    MessageBox.Show("Shared files exist!  " +
                        "This alternate logic depends on files existing in only one location.  " +
                        "Please resolve before reattempting conversion.",
                        "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            });
        }
コード例 #11
0
ファイル: FileAnalyzer.cs プロジェクト: markjforte/vss2git
        public void AddItem(VssProject project)
        {
            if (project == null)
            {
                throw new ArgumentNullException("project");
            }

            PathMatcher exclusionMatcher = null;

            if (!string.IsNullOrEmpty(excludeFiles))
            {
                var excludeFileArray = excludeFiles.Split(
                    new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                exclusionMatcher = new PathMatcher(excludeFileArray);
            }

            workQueue.AddLast(delegate(object work)
            {
                logger.WriteSectionSeparator();
                LogStatus(work, "Building file location dictionary");

                logger.WriteLine("Root project: {0}", project.Path);
                logger.WriteLine("Excluded files: {0}", excludeFiles);

                int excludedFiles = 0;
                var stopwatch     = Stopwatch.StartNew();
                VssUtil.RecurseItems(project,
                                     delegate(VssProject subproject)
                {
                    if (workQueue.IsAborting)
                    {
                        return(RecursionStatus.Abort);
                    }
                    return(RecursionStatus.Continue);
                },
                                     delegate(VssProject subproject, VssFile file)
                {
                    if (workQueue.IsAborting)
                    {
                        return(RecursionStatus.Abort);
                    }

                    var path = file.GetPath(subproject);
                    if (exclusionMatcher != null && exclusionMatcher.Matches(path))
                    {
                        logger.WriteLine("Excluding file {0}", path);
                        ++excludedFiles;
                        return(RecursionStatus.Skip);
                    }

                    // Don't process files in deleted projects
                    if (!projectAnalyzer.DeletedProjects.Contains(subproject.PhysicalName))
                    {
                        ProjectLocation projectLocation;
                        if (!projectAnalyzer.SortedProjectLocations.TryGetValue(subproject.PhysicalName, out projectLocation))
                        {
                            // If the project is not found it is (i.e. should) be due to exclusionMatcher
                            //logger.WriteLine("Unexpected: FileAnalyzer: SortedProjectLocations does not contain project: {0}", subproject.PhysicalName);
                        }
                        else if (!projectLocation.DeletedFiles.Contains(file.PhysicalName))
                        {
                            // If the file is shared it might be in more than one project...
                            // But this should not happen using this alternate import method!
                            if (processedFiles.Contains(file.PhysicalName))
                            {
                                ++sharedFileCount;
                                logger.WriteLine("Unexpected: FileAnalyzer: File shared in more tha one project: {0}: {1}", file.PhysicalName, subproject.Path);
                            }
                            else
                            {
                                processedFiles.Add(file.PhysicalName);
                                FileLocation fileLocation;
                                if (sortedFileLocations.TryGetValue(file.PhysicalName, out fileLocation))
                                {
                                    logger.WriteLine("Unexpected: FileAnalyzer: sortedFileLocations already contains file: {0}", file.PhysicalName);
                                }
                                else
                                {
                                    fileLocation = new FileLocation(file.PhysicalName, file.GetPath(subproject));
                                    sortedFileLocations[file.PhysicalName] = fileLocation;
                                }
                                ++fileCount;
                            }
                        }
                    }

                    return(RecursionStatus.Continue);
                });
                stopwatch.Stop();

                logger.WriteSectionSeparator();
                logger.WriteLine("Analysis complete in {0:HH:mm:ss}", new DateTime(stopwatch.ElapsedTicks));
                logger.WriteLine("Files: {0} ({1} excluded)", fileCount, excludedFiles);
                logger.WriteLine("Shared Files: {0}", sharedFileCount);

                if (sharedFileCount > 0)
                {
                    workQueue.Abort();
                    MessageBox.Show("Shared files exist!  " +
                                    "This alternate logic depends on files existing in only one location.  " +
                                    "Please resolve before reattempting conversion.",
                                    "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            });
        }