コード例 #1
0
        void PopulateFolder(FolderToClean Folder)
        {
            if (!bAbortScan)
            {
                try
                {
                    if ((Folder.Directory.Attributes & FileAttributes.ReparsePoint) == 0)
                    {
                        foreach (DirectoryInfo SubDirectory in Folder.Directory.EnumerateDirectories())
                        {
                            FolderToClean SubFolder = new FolderToClean(SubDirectory);
                            Folder.NameToSubFolder[SubFolder.Name] = SubFolder;
                            QueueFolderToPopulate(SubFolder);
                        }
                        foreach (FileInfo File in Folder.Directory.EnumerateFiles())
                        {
                            FileAttributes Attributes = File.Attributes;                             // Force the value to be cached.
                            Folder.NameToFile[File.Name] = File;
                        }
                    }
                }
                catch (Exception Ex)
                {
                    string NewError = String.Format("Unable to enumerate contents of {0} due to an error:\n\n{1}", Folder.Directory.FullName, Ex);
                    Interlocked.CompareExchange(ref ScanError, NewError, null);
                    bAbortScan = true;
                }
            }

            if (Interlocked.Decrement(ref RemainingFoldersToScan) == 0)
            {
                FinishedScan.Set();
            }
        }
コード例 #2
0
        private CleanWorkspaceWindow(PerforceConnection PerforceClient, FolderToClean RootFolderToClean)
        {
            this.PerforceClient    = PerforceClient;
            this.RootFolderToClean = RootFolderToClean;

            InitializeComponent();
        }
コード例 #3
0
        void PopulateFolder(FolderToClean Folder)
        {
            if (!bAbortScan)
            {
                if ((Folder.Directory.Attributes & FileAttributes.ReparsePoint) == 0)
                {
                    foreach (DirectoryInfo SubDirectory in Folder.Directory.EnumerateDirectories())
                    {
                        FolderToClean SubFolder = new FolderToClean(SubDirectory);
                        Folder.NameToSubFolder[SubFolder.Name] = SubFolder;
                        QueueFolderToPopulate(SubFolder);
                    }
                    foreach (FileInfo File in Folder.Directory.EnumerateFiles())
                    {
                        FileAttributes Attributes = File.Attributes;                         // Force the value to be cached.
                        Folder.NameToFile[File.Name] = File;
                    }
                }
            }

            if (Interlocked.Decrement(ref RemainingFoldersToScan) == 0)
            {
                FinishedScan.Set();
            }
        }
コード例 #4
0
        public static void DoClean(PerforceConnection PerforceClient, string LocalRootPath, string ClientRootPath, IReadOnlyList <string> SyncPaths, TextWriter Log)
        {
            // Figure out which folders to clean
            FolderToClean RootFolderToClean = new FolderToClean(new DirectoryInfo(LocalRootPath));

            using (FindFoldersToCleanTask QueryWorkspace = new FindFoldersToCleanTask(PerforceClient, RootFolderToClean, ClientRootPath, SyncPaths, Log))
            {
                string ErrorMessage;
                if (!ModalTaskWindow.Execute(QueryWorkspace, "Clean Workspace", "Querying files in Perforce, please wait...", out ErrorMessage))
                {
                    if (!String.IsNullOrEmpty(ErrorMessage))
                    {
                        MessageBox.Show(ErrorMessage);
                    }
                    return;
                }
            }

            // If there's nothing to delete, don't bother displaying the dialog at all
            if (RootFolderToClean.FilesToClean.Count == 0 && RootFolderToClean.SubFolders.Count == 0)
            {
                MessageBox.Show("You have no local files which are not in Perforce.", "Workspace Clean", MessageBoxButtons.OK);
                return;
            }

            // Populate the tree
            CleanWorkspaceWindow CleanWorkspace = new CleanWorkspaceWindow(RootFolderToClean);

            CleanWorkspace.ShowDialog();
        }
コード例 #5
0
        void MergeTrees(FolderToClean LocalFolder, PerforceHaveFolder PerforceFolder, HashSet <string> OpenClientPaths)
        {
            if (PerforceFolder == null)
            {
                // Loop through all the local sub-folders
                foreach (FolderToClean LocalSubFolder in LocalFolder.NameToSubFolder.Values)
                {
                    MergeTrees(LocalSubFolder, null, OpenClientPaths);
                }

                // Delete everything
                LocalFolder.FilesToDelete.AddRange(LocalFolder.NameToFile.Values);
            }
            else
            {
                // Loop through all the local sub-folders
                foreach (FolderToClean LocalSubFolder in LocalFolder.NameToSubFolder.Values)
                {
                    PerforceHaveFolder PerforceSubFolder;
                    PerforceFolder.NameToSubFolder.TryGetValue(LocalSubFolder.Name, out PerforceSubFolder);
                    MergeTrees(LocalSubFolder, PerforceSubFolder, OpenClientPaths);
                }

                // Also merge all the Perforce folders that no longer exist
                foreach (KeyValuePair <string, PerforceHaveFolder> PerforceSubFolderPair in PerforceFolder.NameToSubFolder)
                {
                    FolderToClean LocalSubFolder;
                    if (!LocalFolder.NameToSubFolder.TryGetValue(PerforceSubFolderPair.Key, out LocalSubFolder))
                    {
                        LocalSubFolder = new FolderToClean(new DirectoryInfo(Path.Combine(LocalFolder.Directory.FullName, PerforceSubFolderPair.Key)));
                        MergeTrees(LocalSubFolder, PerforceSubFolderPair.Value, OpenClientPaths);
                        LocalFolder.NameToSubFolder.Add(LocalSubFolder.Name, LocalSubFolder);
                    }
                }

                // Find all the files that need to be re-synced
                foreach (KeyValuePair <string, PerforceFileRecord> FilePair in PerforceFolder.NameToFile)
                {
                    FileInfo LocalFile;
                    if (!LocalFolder.NameToFile.TryGetValue(FilePair.Key, out LocalFile))
                    {
                        LocalFolder.FilesToSync.Add(new FileInfo(Path.Combine(LocalFolder.Directory.FullName, FilePair.Key)));
                    }
                    else if ((FilePair.Value.Flags & PerforceFileFlags.AlwaysWritable) == 0 && (LocalFile.Attributes & FileAttributes.ReadOnly) == 0 && !OpenClientPaths.Contains(FilePair.Value.ClientPath))
                    {
                        LocalFolder.FilesToSync.Add(LocalFile);
                    }
                }

                // Find all the files that should be deleted
                LocalFolder.FilesToDelete.AddRange(LocalFolder.NameToFile.Values.Where(x => !PerforceFolder.NameToFile.ContainsKey(x.Name)));
            }

            // Figure out if this folder is just an empty directory that needs to be removed
            LocalFolder.bEmptyLeaf = LocalFolder.NameToFile.Count == 0 && LocalFolder.NameToSubFolder.Count == 0 && LocalFolder.FilesToSync.Count == 0;

            // Figure out if it the folder will be empty after the clean operation
            LocalFolder.bEmptyAfterClean = LocalFolder.NameToSubFolder.Values.All(x => x.bEmptyAfterClean) && LocalFolder.FilesToDelete.Count == LocalFolder.NameToFile.Count && LocalFolder.FilesToSync.Count == 0;
        }
コード例 #6
0
 void RemoveEmptyFolders(FolderToClean Folder)
 {
     foreach (FolderToClean SubFolder in Folder.SubFolders)
     {
         RemoveEmptyFolders(SubFolder);
     }
     Folder.SubFolders.RemoveAll(x => x.SubFolders.Count == 0 && x.FilesToClean.Count == 0);
 }
コード例 #7
0
 void QueueFolderToPopulate(FolderToClean Folder)
 {
     if (Interlocked.Increment(ref RemainingFoldersToScan) == 1)
     {
         FinishedScan.Reset();
     }
     ThreadPool.QueueUserWorkItem(x => PopulateFolder(Folder));
 }
コード例 #8
0
        private TreeNode BuildTreeViewStructure(FolderToClean Folder, string FolderPath, bool bParentFolderSelected, int Depth)
        {
            bool bSelectFolder = bParentFolderSelected || IsSafeToDeleteFolder(FolderPath);

            TreeNodeData FolderNodeData = new TreeNodeData();

            FolderNodeData.Folder = Folder;

            TreeNode FolderNode = new TreeNode();

            FolderNode.Text = Folder.Name;
            FolderNode.Tag  = FolderNodeData;

            foreach (FolderToClean SubFolder in Folder.SubFolders.OrderBy(x => x.Name))
            {
                TreeNode ChildNode = BuildTreeViewStructure(SubFolder, FolderPath + SubFolder.Name.ToLowerInvariant() + "/", bSelectFolder, Depth + 1);
                FolderNode.Nodes.Add(ChildNode);

                TreeNodeData ChildNodeData = (TreeNodeData)ChildNode.Tag;
                FolderNodeData.NumFiles         += ChildNodeData.NumFiles;
                FolderNodeData.NumSelectedFiles += ChildNodeData.NumSelectedFiles;
            }

            foreach (FileInfo File in Folder.FilesToClean.OrderBy(x => x.Name))
            {
                string Name = File.Name.ToLowerInvariant();

                bool bSelectFile = bSelectFolder || IsSafeToDeleteFile(FolderPath, File.Name.ToLowerInvariant());

                TreeNodeData FileNodeData = new TreeNodeData();
                FileNodeData.File             = File;
                FileNodeData.NumFiles         = 1;
                FileNodeData.NumSelectedFiles = bSelectFile? 1 : 0;

                TreeNode FileNode = new TreeNode();
                FileNode.Text = File.Name;
                FileNode.Tag  = FileNodeData;
                FolderNode.Nodes.Add(FileNode);

                UpdateImage(FileNode);

                FolderNodeData.NumFiles++;
                FolderNodeData.NumSelectedFiles += FileNodeData.NumSelectedFiles;
            }

            if (FolderNodeData.NumSelectedFiles > 0 && !FolderNodeData.Folder.bEmptyAfterDelete && Depth < 2)
            {
                FolderNode.Expand();
            }
            else
            {
                FolderNode.Collapse();
            }

            UpdateImage(FolderNode);
            return(FolderNode);
        }
コード例 #9
0
        void RemoveEmptyFolders(FolderToClean Folder)
        {
            foreach (FolderToClean SubFolder in Folder.NameToSubFolder.Values)
            {
                RemoveEmptyFolders(SubFolder);
            }

            Folder.NameToSubFolder = Folder.NameToSubFolder.Values.Where(x => x.NameToSubFolder.Count > 0 || x.FilesToSync.Count > 0 || x.FilesToDelete.Count > 0 || x.bEmptyLeaf).ToDictionary(x => x.Name, x => x, StringComparer.InvariantCultureIgnoreCase);
        }
コード例 #10
0
        private CleanWorkspaceWindow(PerforceConnection PerforceClient, FolderToClean RootFolderToClean, string[] ExtraSafeToDeleteFolders, string[] ExtraSafeToDeleteExtensions)
        {
            this.PerforceClient              = PerforceClient;
            this.RootFolderToClean           = RootFolderToClean;
            this.ExtraSafeToDeleteFolders    = ExtraSafeToDeleteFolders.Select(x => x.Trim().Replace('\\', '/').Trim('/')).Where(x => x.Length > 0).Select(x => String.Format("/{0}/", x.ToLowerInvariant())).ToArray();
            this.ExtraSafeToDeleteExtensions = ExtraSafeToDeleteExtensions.Select(x => x.Trim().ToLowerInvariant()).Where(x => x.Length > 0).ToArray();

            InitializeComponent();
        }
コード例 #11
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);
 }
コード例 #12
0
 void RemoveFilesToKeep(FolderToClean Folder, PerforceHaveFolder KeepFolder)
 {
     foreach (FolderToClean SubFolder in Folder.SubFolders)
     {
         PerforceHaveFolder KeepSubFolder;
         if (KeepFolder.SubFolders.TryGetValue(SubFolder.Directory.Name, out KeepSubFolder))
         {
             RemoveFilesToKeep(SubFolder, KeepSubFolder);
             Folder.bEmptyAfterDelete &= SubFolder.bEmptyAfterDelete;
         }
     }
     Folder.bEmptyAfterDelete &= (Folder.FilesToClean.RemoveAll(x => KeepFolder.Files.Contains(x.Name)) == 0);
 }
コード例 #13
0
        void PopulateFolder(FolderToClean Folder)
        {
            if (!bAbortScan)
            {
                foreach (DirectoryInfo SubDirectory in Folder.Directory.EnumerateDirectories())
                {
                    FolderToClean SubFolder = new FolderToClean(SubDirectory);
                    Folder.SubFolders.Add(SubFolder);
                    QueueFolderToPopulate(SubFolder);
                }
                Folder.FilesToClean = Folder.Directory.EnumerateFiles().ToList();
            }

            if (Interlocked.Decrement(ref RemainingFoldersToScan) == 0)
            {
                FinishedScan.Set();
            }
        }
コード例 #14
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();
                    }
                }
            }
        }
コード例 #15
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();
					}
				}
			}
		}
コード例 #16
0
        void PopulateFolder(FolderToClean Folder)
        {
            if (!bAbortScan)
            {
                if ((Folder.Directory.Attributes & FileAttributes.ReparsePoint) == 0)
                {
                    foreach (DirectoryInfo SubDirectory in Folder.Directory.EnumerateDirectories())
                    {
                        FolderToClean SubFolder = new FolderToClean(SubDirectory);
                        Folder.SubFolders.Add(SubFolder);
                        QueueFolderToPopulate(SubFolder);
                    }
                    Folder.FilesToClean = Folder.Directory.EnumerateFiles().ToList();
                }
                Folder.bEmptyLeaf = Folder.SubFolders.Count == 0 && Folder.FilesToClean.Count == 0;
            }

            if (Interlocked.Decrement(ref RemainingFoldersToScan) == 0)
            {
                FinishedScan.Set();
            }
        }
コード例 #17
0
        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);
        }
コード例 #18
0
		void RemoveEmptyFolders(FolderToClean Folder)
		{
			foreach(FolderToClean SubFolder in Folder.SubFolders)
			{
				RemoveEmptyFolders(SubFolder);
			}
			Folder.SubFolders.RemoveAll(x => x.SubFolders.Count == 0 && x.FilesToClean.Count == 0 && !x.bEmptyLeaf);
		}
コード例 #19
0
		void RemoveFilesToKeep(FolderToClean Folder, PerforceHaveFolder KeepFolder)
		{
			foreach(FolderToClean SubFolder in Folder.SubFolders)
			{
				PerforceHaveFolder KeepSubFolder;
				if(KeepFolder.SubFolders.TryGetValue(SubFolder.Directory.Name, out KeepSubFolder))
				{
					RemoveFilesToKeep(SubFolder, KeepSubFolder);
					Folder.bEmptyAfterDelete &= SubFolder.bEmptyAfterDelete;
				}
			}
			Folder.bEmptyAfterDelete &= (Folder.FilesToClean.RemoveAll(x => KeepFolder.Files.Contains(x.Name)) == 0);
		}
コード例 #20
0
        private TreeNode BuildTreeViewStructure(FolderToClean Folder, string FolderPath, bool bParentFolderSelected, int Depth)
        {
            bool bSelectFolder = bParentFolderSelected || IsSafeToDeleteFolder(FolderPath) || Folder.bEmptyLeaf;

            TreeNodeData FolderNodeData = new TreeNodeData();

            FolderNodeData.Folder = Folder;

            TreeNode FolderNode = new TreeNode();

            FolderNode.Text = Folder.Name;
            FolderNode.Tag  = FolderNodeData;

            foreach (FolderToClean SubFolder in Folder.NameToSubFolder.OrderBy(x => x.Key).Select(x => x.Value))
            {
                TreeNode ChildNode = BuildTreeViewStructure(SubFolder, FolderPath + SubFolder.Name.ToLowerInvariant() + "/", bSelectFolder, Depth + 1);
                FolderNode.Nodes.Add(ChildNode);

                TreeNodeData ChildNodeData = (TreeNodeData)ChildNode.Tag;
                FolderNodeData.NumFiles                += ChildNodeData.NumFiles;
                FolderNodeData.NumSelectedFiles        += ChildNodeData.NumSelectedFiles;
                FolderNodeData.NumEmptySelectedFiles   += ChildNodeData.NumEmptySelectedFiles;
                FolderNodeData.NumMissingSelectedFiles += ChildNodeData.NumMissingSelectedFiles;
                FolderNodeData.NumDefaultSelectedFiles += ChildNodeData.NumDefaultSelectedFiles;
            }

            foreach (FileInfo File in Folder.FilesToSync.OrderBy(x => x.Name))
            {
                TreeNodeData FileNodeData = new TreeNodeData();
                FileNodeData.Action                  = TreeNodeAction.Sync;
                FileNodeData.File                    = File;
                FileNodeData.NumFiles                = 1;
                FileNodeData.NumSelectedFiles        = 1;
                FileNodeData.NumEmptySelectedFiles   = 0;
                FileNodeData.NumMissingSelectedFiles = 1;
                FileNodeData.NumDefaultSelectedFiles = FileNodeData.NumSelectedFiles;

                TreeNode FileNode = new TreeNode();
                FileNode.Text = File.Name + " (sync)";
                FileNode.Tag  = FileNodeData;
                FolderNode.Nodes.Add(FileNode);

                UpdateImage(FileNode);

                FolderNodeData.NumFiles++;
                FolderNodeData.NumSelectedFiles        += FileNodeData.NumSelectedFiles;
                FolderNodeData.NumEmptySelectedFiles   += FileNodeData.NumEmptySelectedFiles;
                FolderNodeData.NumMissingSelectedFiles += FileNodeData.NumMissingSelectedFiles;
                FolderNodeData.NumDefaultSelectedFiles += FileNodeData.NumDefaultSelectedFiles;
            }

            foreach (FileInfo File in Folder.FilesToDelete.OrderBy(x => x.Name))
            {
                string Name = File.Name.ToLowerInvariant();

                bool bSelectFile = bSelectFolder || IsSafeToDeleteFile(FolderPath, File.Name.ToLowerInvariant());

                TreeNodeData FileNodeData = new TreeNodeData();
                FileNodeData.Action                  = TreeNodeAction.Delete;
                FileNodeData.File                    = File;
                FileNodeData.NumFiles                = 1;
                FileNodeData.NumSelectedFiles        = bSelectFile? 1 : 0;
                FileNodeData.NumEmptySelectedFiles   = 0;
                FileNodeData.NumMissingSelectedFiles = 0;
                FileNodeData.NumDefaultSelectedFiles = FileNodeData.NumSelectedFiles;

                TreeNode FileNode = new TreeNode();
                FileNode.Text = File.Name;
                FileNode.Tag  = FileNodeData;
                FolderNode.Nodes.Add(FileNode);

                UpdateImage(FileNode);

                FolderNodeData.NumFiles++;
                FolderNodeData.NumSelectedFiles        += FileNodeData.NumSelectedFiles;
                FolderNodeData.NumEmptySelectedFiles   += FileNodeData.NumEmptySelectedFiles;
                FolderNodeData.NumMissingSelectedFiles += FileNodeData.NumMissingSelectedFiles;
                FolderNodeData.NumDefaultSelectedFiles += FileNodeData.NumDefaultSelectedFiles;
            }

            if (FolderNodeData.Folder.bEmptyLeaf)
            {
                FolderNodeData.NumFiles++;
                FolderNodeData.NumSelectedFiles++;
                FolderNodeData.NumEmptySelectedFiles++;
                FolderNodeData.NumDefaultSelectedFiles++;
            }

            if (FolderNodeData.NumSelectedFiles > 0 && !FolderNodeData.Folder.bEmptyAfterClean && Depth < 2)
            {
                FolderNode.Expand();
            }
            else
            {
                FolderNode.Collapse();
            }

            UpdateImage(FolderNode);
            return(FolderNode);
        }
コード例 #21
0
 private CleanWorkspaceWindow(FolderToClean InRootFolderToClean)
 {
     RootFolderToClean = InRootFolderToClean;
     InitializeComponent();
 }
コード例 #22
0
		void QueueFolderToPopulate(FolderToClean Folder)
		{
			if(Interlocked.Increment(ref RemainingFoldersToScan) == 1)
			{
				FinishedScan.Reset();
			}
			ThreadPool.QueueUserWorkItem(x => PopulateFolder(Folder));
		}
コード例 #23
0
		void PopulateFolder(FolderToClean Folder)
		{
			if(!bAbortScan)
			{
				foreach(DirectoryInfo SubDirectory in Folder.Directory.EnumerateDirectories())
				{
					FolderToClean SubFolder = new FolderToClean(SubDirectory);
					Folder.SubFolders.Add(SubFolder);
					QueueFolderToPopulate(SubFolder);
				}
				Folder.FilesToClean = Folder.Directory.EnumerateFiles().ToList();
				Folder.bEmptyLeaf = Folder.SubFolders.Count == 0 && Folder.FilesToClean.Count == 0;
			}

			if(Interlocked.Decrement(ref RemainingFoldersToScan) == 0)
			{
				FinishedScan.Set();
			}
		}
コード例 #24
0
		private CleanWorkspaceWindow(FolderToClean InRootFolderToClean)
		{
			RootFolderToClean = InRootFolderToClean;
			InitializeComponent();
		}
コード例 #25
0
		private TreeNode BuildTreeViewStructure(FolderToClean Folder, string FolderPath, bool bParentFolderSelected, int Depth)
		{
			bool bSelectFolder = bParentFolderSelected || IsSafeToDeleteFolder(FolderPath) || Folder.bEmptyLeaf;

			TreeNodeData FolderNodeData = new TreeNodeData();
			FolderNodeData.Folder = Folder;

			TreeNode FolderNode = new TreeNode();
			FolderNode.Text = Folder.Name;
			FolderNode.Tag = FolderNodeData;

			foreach(FolderToClean SubFolder in Folder.SubFolders.OrderBy(x => x.Name))
			{
				TreeNode ChildNode = BuildTreeViewStructure(SubFolder, FolderPath + SubFolder.Name.ToLowerInvariant() + "/", bSelectFolder, Depth + 1);
				FolderNode.Nodes.Add(ChildNode);

				TreeNodeData ChildNodeData = (TreeNodeData)ChildNode.Tag;
				FolderNodeData.NumFiles += ChildNodeData.NumFiles;
				FolderNodeData.NumSelectedFiles += ChildNodeData.NumSelectedFiles;
				FolderNodeData.NumEmptySelectedFiles += ChildNodeData.NumEmptySelectedFiles;
				FolderNodeData.NumDefaultSelectedFiles += ChildNodeData.NumDefaultSelectedFiles;
			}

			foreach(FileInfo File in Folder.FilesToClean.OrderBy(x => x.Name))
			{
				string Name = File.Name.ToLowerInvariant();

				bool bSelectFile = bSelectFolder || IsSafeToDeleteFile(FolderPath, File.Name.ToLowerInvariant());

				TreeNodeData FileNodeData = new TreeNodeData();
				FileNodeData.File = File;
				FileNodeData.NumFiles = 1;
				FileNodeData.NumSelectedFiles = bSelectFile? 1 : 0;
				FileNodeData.NumEmptySelectedFiles = 0;
				FileNodeData.NumDefaultSelectedFiles = FileNodeData.NumSelectedFiles;

				TreeNode FileNode = new TreeNode();
				FileNode.Text = File.Name;
				FileNode.Tag = FileNodeData;
				FolderNode.Nodes.Add(FileNode);

				UpdateImage(FileNode);

				FolderNodeData.NumFiles++;
				FolderNodeData.NumSelectedFiles += FileNodeData.NumSelectedFiles;
				FolderNodeData.NumEmptySelectedFiles += FileNodeData.NumEmptySelectedFiles;
				FolderNodeData.NumDefaultSelectedFiles += FileNodeData.NumDefaultSelectedFiles;
			}

			if(FolderNodeData.Folder.bEmptyLeaf)
			{
				FolderNodeData.NumFiles++;
				FolderNodeData.NumSelectedFiles++;
				FolderNodeData.NumEmptySelectedFiles++;
				FolderNodeData.NumDefaultSelectedFiles++;
			}

			if(FolderNodeData.NumSelectedFiles > 0 && !FolderNodeData.Folder.bEmptyAfterDelete && Depth < 2)
			{
				FolderNode.Expand();
			}
			else
			{
				FolderNode.Collapse();
			}

			UpdateImage(FolderNode);
			return FolderNode;
		}
コード例 #26
0
		public static void DoClean(PerforceConnection PerforceClient, string LocalRootPath, string ClientRootPath, IReadOnlyList<string> SyncPaths, TextWriter Log)
		{
			// Figure out which folders to clean
			FolderToClean RootFolderToClean = new FolderToClean(new DirectoryInfo(LocalRootPath));
			using(FindFoldersToCleanTask QueryWorkspace = new FindFoldersToCleanTask(PerforceClient, RootFolderToClean, ClientRootPath, SyncPaths, Log))
			{
				string ErrorMessage;
				if(!ModalTaskWindow.Execute(QueryWorkspace, "Clean Workspace", "Querying files in Perforce, please wait...", out ErrorMessage))
				{
					if(!String.IsNullOrEmpty(ErrorMessage))
					{
						MessageBox.Show(ErrorMessage);
					}
					return;
				}
			}

			// If there's nothing to delete, don't bother displaying the dialog at all
			if(RootFolderToClean.FilesToClean.Count == 0 && RootFolderToClean.SubFolders.Count == 0)
			{
				MessageBox.Show("You have no local files which are not in Perforce.", "Workspace Clean", MessageBoxButtons.OK);
				return;
			}

			// Populate the tree
			CleanWorkspaceWindow CleanWorkspace = new CleanWorkspaceWindow(RootFolderToClean);
			CleanWorkspace.ShowDialog();
		}