// ------------------------------------------------------------------------ // run a HG root status query and get the resulting status informations to a fileStatusDictionary // ------------------------------------------------------------------------ public static bool QueryRootStatus(string rootDirectory, out Dictionary <string, char> fileStatusDictionary) { Trace.WriteLine("Start QueryRootStatus"); fileStatusDictionary = null; if (rootDirectory != string.Empty) { fileStatusDictionary = new Dictionary <string, char>(); // Start a new process for the cmd Process process = HG.InvokeCommand(rootDirectory, "status -m -a -r -d -c -C "); List <string> lines = new List <string>(); string str = ""; while (!process.HasExited) { while ((str = process.StandardOutput.ReadLine()) != null) { lines.Add(str); } Thread.Sleep(0); } while ((str = process.StandardOutput.ReadLine()) != null) { lines.Add(str); } Dictionary <string, string> renamedToOrgFileDictionary = new Dictionary <string, string>(); UpdateStatusDictionary(lines, rootDirectory, fileStatusDictionary, renamedToOrgFileDictionary); } return(fileStatusDictionary != null); }
// ------------------------------------------------------------------------ /// add file to the repositiry if they are not on the ignore list // ------------------------------------------------------------------------ public void AddNotIgnoredFiles(string[] fileListRaw) { // filter already known files from the list List <string> fileList = new List <string>(); lock (_fileStatusDictionary) { foreach (string file in fileListRaw) { HGFileStatusInfo info; if (!_fileStatusDictionary.TryGetValue(file.ToLower(), out info) || info.status != HGFileStatus.scsIgnored) { fileList.Add(file); } } } if (fileList.Count == 0) { return; } SkipDirstate(true); Dictionary <string, char> fileStatusDictionary; if (HG.AddFilesNotIgnored(fileList.ToArray(), out fileStatusDictionary)) { _fileStatusDictionary.Add(fileStatusDictionary); } SkipDirstate(false); }
// ------------------------------------------------------------------------ /// enter file renamed to hg repository // ------------------------------------------------------------------------ public void EnterFileRenamed(string[] oldFileNames, string[] newFileNames) { var oNameList = new List <string> (); var nNameList = new List <string>(); lock (_fileStatusDictionary) { for (int pos = 0; pos < oldFileNames.Length; ++pos) { string oFileName = oldFileNames[pos]; string nFileName = newFileNames[pos]; if (nFileName.EndsWith("\\")) { // this is an dictionary - skip it } else if (oFileName.ToLower() != nFileName.ToLower()) { oNameList.Add(oFileName); nNameList.Add(nFileName); _fileStatusDictionary.Remove(oFileName); _fileStatusDictionary.Remove(nFileName); } } } if (oNameList.Count > 0) { SkipDirstate(true); HG.EnterFileRenamed(oNameList.ToArray(), nNameList.ToArray()); SkipDirstate(false); } }
// ------------------------------------------------------------------------ // build the argument sting from the given files and call invoke the hg command // ------------------------------------------------------------------------ static void InvokeCommand(string command, string[] fileList, bool directoriesAllowed) { string workingDirectory = fileList[0].Substring(0, fileList[0].LastIndexOf('\\')); string rootDirectory = HG.FindRootDirectory(workingDirectory); List <string> list; string commandString = command; int counter = 0; foreach (var file in fileList) { ++counter; if (!directoriesAllowed && file.EndsWith("\\")) { continue; } commandString += " \"" + file.Substring(rootDirectory.Length + 1) + "\" "; if (counter > 20 || commandString.Length > 1024) { HG.InvokeCommand(rootDirectory, commandString, out list); commandString = command; } } HG.InvokeCommand(rootDirectory, commandString, out list); }
// ------------------------------------------------------------------------ /// Add a root directory and query the status of the contining files /// by a QueryRootStatus call. // ------------------------------------------------------------------------ public bool AddRootDirectory(string directory) { if (directory == string.Empty) { return(false); } string root = HG.FindRootDirectory(directory); if (root != string.Empty && !_rootDirMap.ContainsKey(root)) { _rootDirMap[root] = new RootInfo() { _Branch = HG.GetCurrentBranchName(root) }; if (!_directoryWatcherMap.ContainsDirectory(root)) { _directoryWatcherMap.WatchDirectory(root); } Dictionary <string, char> fileStatusDictionary; if (HG.QueryRootStatus(root, out fileStatusDictionary)) { _fileStatusDictionary.Add(fileStatusDictionary); } } return(true); }
// ------------------------------------------------------------------------ // update file status of the watched dirty files // ------------------------------------------------------------------------ bool UpdateFileStatusDictionary(List <string> fileList) { bool updateUI = false; if (_bRebuildStatusCacheRequired) { return(false); } // now we will get HG status information for the remaining files if (!_bRebuildStatusCacheRequired && fileList.Count > 0) { Dictionary <string, char> fileStatusDictionary; SkipDirstate(true); if (HG.QueryFileStatus(fileList.ToArray(), out fileStatusDictionary)) { Trace.WriteLine("got status for watched files - count: " + fileStatusDictionary.Count.ToString()); lock (_fileStatusDictionary) { _fileStatusDictionary.Add(fileStatusDictionary); } } SkipDirstate(false); updateUI = true; } return(updateUI); }
// ------------------------------------------------------------------------ /// update given file status. // ------------------------------------------------------------------------ public void UpdateFileStatus(string[] files) { Dictionary <string, char> fileStatusDictionary; if (HG.QueryFileStatus(files, out fileStatusDictionary)) { _fileStatusDictionary.Add(fileStatusDictionary); } }
// ------------------------------------------------------------------------ // update given root files status. // ------------------------------------------------------------------------ public void UpdateFileStatus(string root) { Dictionary <string, char> fileStatusDictionary; if (HG.QueryRootStatus(root, out fileStatusDictionary)) { _fileStatusDictionary.Add(fileStatusDictionary); } }
// ------------------------------------------------------------------------ // query the files status and get them to the fileStatusDictionary // ------------------------------------------------------------------------ static public bool QueryFileStatus(string[] fileList, out Dictionary <string, char> fileStatusDictionary, out Dictionary <string, string> renamedToOrgFileDictionary) { fileStatusDictionary = new Dictionary <string, char>(); renamedToOrgFileDictionary = new Dictionary <string, string>(); Dictionary <string, string> commandLines = new Dictionary <string, string>(); try { if (fileList.Length > 0) { for (int iFile = 0; iFile < fileList.Length; ++iFile) { string file = fileList[iFile]; string rootDirectory = HG.FindRootDirectory(file); string commandLine = ""; commandLines.TryGetValue(rootDirectory, out commandLine); commandLine += " \"" + file.Substring(rootDirectory.Length + 1) + "\" "; if (commandLine.Length >= (2000)) { List <string> resultList; InvokeCommand(rootDirectory, "status -A " + commandLine, out resultList); UpdateStatusDictionary(resultList, rootDirectory, fileStatusDictionary, renamedToOrgFileDictionary); // reset cmd line and filecounter for the next run commandLine = ""; } commandLines[rootDirectory] = commandLine; } foreach (KeyValuePair <string, string> directoryCommandLine in commandLines) { string rootDirectory = directoryCommandLine.Key; string commandLine = directoryCommandLine.Value; if (commandLine.Length > 0) { List <string> resultList; InvokeCommand(rootDirectory, "status -A " + commandLine, out resultList); UpdateStatusDictionary(resultList, rootDirectory, fileStatusDictionary, renamedToOrgFileDictionary); } } } } catch (Exception ex) { Trace.WriteLine("HGProcess.QueryFileStatus: " + ex.Message); return(false); } return(fileStatusDictionary != null); }
// ------------------------------------------------------------------------ // get current used brunchname of repository // ------------------------------------------------------------------------ public static string GetCurrentBranchName(string rootDirectory) { string branchName = ""; List <string> resultList; HG.InvokeCommand(rootDirectory, "branch", out resultList); if (resultList.Count > 0) { branchName = resultList[0]; } return(branchName); }
// ------------------------------------------------------------------------ // rebuild the entire _fileStatusDictionary map // this includes all files in all watched directories // ------------------------------------------------------------------------ void RebuildStatusCache() { // remove all status entries _fileStatusDictionary.Clear(); _bRebuildStatusCacheRequired = false; SkipDirstate(true); HGFileStatusInfoDictionary newFileStatusDictionary = new HGFileStatusInfoDictionary(); foreach (var directoryWatcher in _directoryWatcherMap.WatcherList) { // reset the watcher map directoryWatcher.Value.PopDirtyFilesMap(); } List <string> rootDirList = null; lock (_rootDirMap) { rootDirList = new List <string>(_rootDirMap.Keys); } // sort dirs by lenght to query from root top to down root rootDirList.Sort((a, b) => ((a.Length == b.Length) ? 0 : ((a.Length > b.Length) ? 1 : -1))); foreach (string rootDirectory in rootDirList) { if (rootDirectory != string.Empty) { _rootDirMap[rootDirectory]._Branch = HG.GetCurrentBranchName(rootDirectory); Dictionary <string, char> fileStatusDictionary; if (HG.QueryRootStatus(rootDirectory, out fileStatusDictionary)) { Trace.WriteLine("RebuildStatusCache - number of files: " + fileStatusDictionary.Count.ToString()); newFileStatusDictionary.Add(fileStatusDictionary); } } } lock (_fileStatusDictionary) { _fileStatusDictionary = newFileStatusDictionary; } SkipDirstate(false); }
// ------------------------------------------------------------------------ // invoke the given command and get the new status of dependend files // to the dictionary // ------------------------------------------------------------------------ static bool InvokeCommandGetStatus(string cmd, string[] fileList, out Dictionary <string, char> fileStatusDictionary) { fileStatusDictionary = null; try { HG.InvokeCommand(cmd, fileList, false); if (!QueryFileStatus(fileList, out fileStatusDictionary)) { fileStatusDictionary = null; } } catch (Exception ex) { Trace.WriteLine("cmd- " + ex.Message); return(false); } return(fileStatusDictionary != null); }
public static string GetHGTKFileName() { if (hgtkexe == null || hgtkexe == string.Empty) { hgtkexe = HG.GetTortoiseHGDirectory(); if (hgtkexe != null && hgtkexe != string.Empty) { if (File.Exists(hgtkexe + "HGTK.exe")) { hgtkexe += "HGTK.exe"; } else if (File.Exists(hgtkexe + "THG.exe")) { hgtkexe += "THG.exe"; } } } return(hgtkexe); }
// ------------------------------------------------------------------------ // file was removed - now update the hg repository // ------------------------------------------------------------------------ public void EnterFilesRemoved(string[] fileList) { List <string> removedFileList = new List <string>(); List <string> movedFileList = new List <string>(); List <string> newNamesList = new List <string>(); lock (_fileStatusDictionary) { foreach (var file in fileList) { _fileStatusDictionary.Remove(file); string newName; if (!_fileStatusDictionary.FileMoved(file, out newName)) { removedFileList.Add(file); } else { movedFileList.Add(file); newNamesList.Add(newName); } } } if (movedFileList.Count > 0) { EnterFileRenamed(movedFileList.ToArray(), newNamesList.ToArray()); } if (removedFileList.Count > 0) { SkipDirstate(true); // avoid a status requery for the repo after hg.dirstate was changed Dictionary <string, char> fileStatusDictionary; if (HG.EnterFileRemoved(removedFileList.ToArray(), out fileStatusDictionary)) { _fileStatusDictionary.Add(fileStatusDictionary); } SkipDirstate(false); } }
// ------------------------------------------------------------------------ // show TortoiseHG status dialog // ------------------------------------------------------------------------ static public Process DiffDialog(string sccFile, string file, string commandMask) { String root = HGLib.HG.FindRootDirectory(file); if (root != String.Empty) { // copy latest file revision from repo temp folder string currentFile = file; string versionedFile = Path.GetTempPath() + sccFile.Substring(sccFile.LastIndexOf("\\") + 1) + "(base)"; // delete file if exists File.Delete(versionedFile); string cmd = "cat \"" + sccFile.Substring(root.Length + 1) + "\" -o \"" + versionedFile + "\""; InvokeCommand(HG.GetHGFileName(), root, cmd); // wait file exists on disk int counter = 0; while (!File.Exists(versionedFile) && counter < 10) { Thread.Sleep(100); ++counter; } // run diff tool if (commandMask != string.Empty) { cmd = PrepareDiffCommand(versionedFile, currentFile, commandMask); return(InvokeCommand(cmd, "", "")); } else { commandMask = " \"$(Base)\" --fname \"$(BaseName)\" \"$(Mine)\" --fname \"$(MineName)\" "; cmd = PrepareDiffCommand(versionedFile, currentFile, commandMask); return(InvokeCommand(HG.GetTortoiseHGDirectory() + "kdiff3.exe", root, cmd)); } } return(null); }
// ------------------------------------------------------------------------ // detect moved files // ------------------------------------------------------------------------ public bool FileMoved(string fileName, out string newName) { string root = HG.FindRootDirectory(fileName); string name = Path.GetFileName(fileName); foreach (HGFileStatusInfo value in _dictionary.Values) { if (value.status == HGLib.HGFileStatus.scsAdded) { if (name.Equals(value.fileName, StringComparison.CurrentCultureIgnoreCase)) { string root2 = HG.FindRootDirectory(value.fullPath); if (root.Equals(root2, StringComparison.CurrentCultureIgnoreCase)) { newName = value.fullPath; return(true); } } } } newName = ""; return(false); }
// ------------------------------------------------------------------------ // enter file renamed to hg repository // ------------------------------------------------------------------------ static public bool EnterFileRenamed(string[] orgFileName, string[] newFileName) { try { for (int pos = 0; pos < orgFileName.Length; ++pos) { string workingDirectory = orgFileName[pos].Substring(0, orgFileName[pos].LastIndexOf('\\')); string rootDirectory = HG.FindRootDirectory(workingDirectory); string ofile = orgFileName[pos].Substring(rootDirectory.Length + 1); string nfile = newFileName[pos].Substring(rootDirectory.Length + 1); List <string> list; HG.InvokeCommand(rootDirectory, "rename -A \"" + ofile + "\" \"" + nfile + "\"", out list); } } catch (Exception ex) { Trace.WriteLine("HG.EnterFileRenamed exception- " + ex.Message); return(false); } return(true); }
// ------------------------------------------------------------------------ // async proc to assimilate the directory watcher state dictionaries // ------------------------------------------------------------------------ void DirectoryStatusCheckerThread(object source, ElapsedEventArgs e) { // handle user and IDE commands first Queue <IHGWorkItem> workItemQueue = _workItemQueue.PopWorkItems(); if (workItemQueue.Count > 0) { List <string> ditryFilesList = new List <string>(); foreach (IHGWorkItem item in workItemQueue) { item.Do(this, ditryFilesList); } if (ditryFilesList.Count > 0) { Dictionary <string, char> fileStatusDictionary; if (HG.QueryFileStatus(ditryFilesList.ToArray(), out fileStatusDictionary)) { lock (_fileStatusDictionary) { _fileStatusDictionary.Add(fileStatusDictionary); } } } // update status icons FireStatusChanged(_context); } else if (!_IsSolutionBuilding) { // handle modified files list long numberOfControlledFiles = 0; lock (_fileStatusDictionary) { numberOfControlledFiles = System.Math.Max(1, _fileStatusDictionary.Count); } long numberOfChangedFiles = 0; double elapsedMS = 0; lock (_directoryWatcherMap) { numberOfChangedFiles = _directoryWatcherMap.GetNumberOfChangedFiles(); TimeSpan timeSpan = new TimeSpan(DateTime.Now.Ticks - _directoryWatcherMap.GetLatestChange().Ticks); elapsedMS = timeSpan.TotalMilliseconds; } if (_bRebuildStatusCacheRequired || numberOfChangedFiles > 200) { if (elapsedMS > _MinElapsedTimeForStatusCacheRebuildMS) { Trace.WriteLine("DoFullStatusUpdate (NumberOfChangedFiles: " + numberOfChangedFiles.ToString() + " )"); RebuildStatusCache(); // update status icons FireStatusChanged(_context); } } else if (numberOfChangedFiles > 0) { // min elapsed time before do anything if (elapsedMS > 2000) { Trace.WriteLine("UpdateDirtyFilesStatus (NumberOfChangedFiles: " + numberOfChangedFiles.ToString() + " )"); var fileList = PopDirtyWatcherFiles(); if (UpdateFileStatusDictionary(fileList)) { // update status icons - but only if a project file was changed bool bFireStatusChanged = false; lock (_FileToProjectCache) { foreach (string file in fileList) { object o; if (_FileToProjectCache.TryGetValue(file.ToLower(), out o)) { bFireStatusChanged = true; break; } } } if (bFireStatusChanged) { FireStatusChanged(_context); } } } } } _timerDirectoryStatusChecker.Enabled = true; }