Пример #1
0
        public FindFoldersToCleanTask(PerforceConnection InPerforceClient, FolderToClean InRootFolderToClean, string InClientRootPath, IReadOnlyList <string> InSyncPaths, TextWriter InLog)
        {
            PerforceClient    = InPerforceClient;
            ClientRootPath    = InClientRootPath.TrimEnd('/') + "/";
            SyncPaths         = new List <string>(InSyncPaths);
            Log               = InLog;
            RootFolderToClean = InRootFolderToClean;
            FinishedScan      = new ManualResetEvent(true);

            foreach (string SyncPath in SyncPaths)
            {
                Debug.Assert(SyncPath.StartsWith(ClientRootPath));
                if (SyncPath.StartsWith(ClientRootPath, StringComparison.InvariantCultureIgnoreCase))
                {
                    string[] Fragments = SyncPath.Substring(ClientRootPath.Length).Split('/');

                    FolderToClean SyncFolder = RootFolderToClean;
                    for (int Idx = 0; Idx < Fragments.Length - 1; Idx++)
                    {
                        FolderToClean NextSyncFolder = SyncFolder.SubFolders.FirstOrDefault(x => x.Name.Equals(Fragments[Idx], StringComparison.InvariantCultureIgnoreCase));
                        if (NextSyncFolder == null)
                        {
                            NextSyncFolder = new FolderToClean(new DirectoryInfo(Path.Combine(SyncFolder.Directory.FullName, Fragments[Idx])));
                            SyncFolder.SubFolders.Add(NextSyncFolder);
                        }
                        SyncFolder = NextSyncFolder;
                    }

                    string Wildcard = Fragments[Fragments.Length - 1];
                    if (Wildcard == "...")
                    {
                        QueueFolderToPopulate(SyncFolder);
                    }
                    else if (SyncFolder.Directory.Exists)
                    {
                        SyncFolder.FilesToClean = SyncFolder.FilesToClean.Union(SyncFolder.Directory.GetFiles(Wildcard)).GroupBy(x => x.Name).Select(x => x.First()).ToList();
                    }
                }
            }
        }
        public bool Run(out string ErrorMessage)
        {
            Log.WriteLine("Finding files in workspace...");
            Log.WriteLine();

            // Start enumerating all the files that exist locally
            foreach (string SyncPath in SyncPaths)
            {
                Debug.Assert(SyncPath.StartsWith(ClientRootPath));
                if (SyncPath.StartsWith(ClientRootPath, StringComparison.InvariantCultureIgnoreCase))
                {
                    string[] Fragments = SyncPath.Substring(ClientRootPath.Length).Split('/');

                    FolderToClean SyncFolder = RootFolderToClean;
                    for (int Idx = 0; Idx < Fragments.Length - 1; Idx++)
                    {
                        FolderToClean NextSyncFolder;
                        if (!SyncFolder.NameToSubFolder.TryGetValue(Fragments[Idx], out NextSyncFolder))
                        {
                            NextSyncFolder = new FolderToClean(new DirectoryInfo(Path.Combine(SyncFolder.Directory.FullName, Fragments[Idx])));
                            SyncFolder.NameToSubFolder[NextSyncFolder.Name] = NextSyncFolder;
                        }
                        SyncFolder = NextSyncFolder;
                    }

                    string Wildcard = Fragments[Fragments.Length - 1];
                    if (Wildcard == "...")
                    {
                        QueueFolderToPopulate(SyncFolder);
                    }
                    else
                    {
                        if (SyncFolder.Directory.Exists)
                        {
                            foreach (FileInfo File in SyncFolder.Directory.EnumerateFiles(Wildcard))
                            {
                                SyncFolder.NameToFile[File.Name] = File;
                            }
                        }
                    }
                }
            }

            // Get the prefix for any local file
            string LocalRootPrefix = RootFolderToClean.Directory.FullName.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar;

            // Query the have table and build a separate tree from it
            PerforceHaveFolder RootHaveFolder = new PerforceHaveFolder();

            foreach (string SyncPath in SyncPaths)
            {
                List <PerforceFileRecord> FileRecords;
                if (!PerforceClient.Stat(String.Format("{0}#have", SyncPath), out FileRecords, Log))
                {
                    ErrorMessage = "Couldn't query have table from Perforce.";
                    return(false);
                }
                foreach (PerforceFileRecord FileRecord in FileRecords)
                {
                    if (!FileRecord.ClientPath.StartsWith(LocalRootPrefix, StringComparison.InvariantCultureIgnoreCase))
                    {
                        ErrorMessage = String.Format("Failed to get have table; file '{0}' doesn't start with root path ('{1}')", FileRecord.ClientPath, RootFolderToClean.Directory.FullName);
                        return(false);
                    }

                    string[] Tokens = FileRecord.ClientPath.Substring(LocalRootPrefix.Length).Split('/', '\\');

                    PerforceHaveFolder FileFolder = RootHaveFolder;
                    for (int Idx = 0; Idx < Tokens.Length - 1; Idx++)
                    {
                        PerforceHaveFolder NextFileFolder;
                        if (!FileFolder.NameToSubFolder.TryGetValue(Tokens[Idx], out NextFileFolder))
                        {
                            NextFileFolder = new PerforceHaveFolder();
                            FileFolder.NameToSubFolder.Add(Tokens[Idx], NextFileFolder);
                        }
                        FileFolder = NextFileFolder;
                    }
                    FileFolder.NameToFile[Tokens[Tokens.Length - 1]] = FileRecord;
                }
            }

            // Find all the files which are currently open for edit. We don't want to force sync these.
            List <PerforceFileRecord> OpenFileRecords;

            if (!PerforceClient.GetOpenFiles("//...", out OpenFileRecords, Log))
            {
                ErrorMessage = "Couldn't query open files from Perforce.";
                return(false);
            }

            // Build a set of all the open local files
            HashSet <string> OpenLocalFiles = new HashSet <string>(StringComparer.InvariantCultureIgnoreCase);

            foreach (PerforceFileRecord OpenFileRecord in OpenFileRecords)
            {
                if (!OpenFileRecord.ClientPath.StartsWith(ClientRootPath, StringComparison.InvariantCultureIgnoreCase))
                {
                    ErrorMessage = String.Format("Failed to get open file list; file '{0}' doesn't start with client root path ('{1}')", OpenFileRecord.ClientPath, ClientRootPath);
                    return(false);
                }
                OpenLocalFiles.Add(LocalRootPrefix + PerforceUtils.UnescapePath(OpenFileRecord.ClientPath).Substring(ClientRootPath.Length).Replace('/', Path.DirectorySeparatorChar));
            }

            // Wait to finish scanning the directory
            FinishedScan.WaitOne();

            // Find the value of the P4CONFIG variable
            string PerforceConfigFile;

            PerforceClient.GetSetting("P4CONFIG", out PerforceConfigFile, Log);

            // Merge the trees
            MergeTrees(RootFolderToClean, RootHaveFolder, OpenLocalFiles, PerforceConfigFile);

            // Remove all the empty folders
            RemoveEmptyFolders(RootFolderToClean);
            ErrorMessage = null;
            return(true);
        }