// Read a string std::string TortoiseRegistryCache::ReadString(const std::string& key, const std::string& name, const std::string& defaultValue, bool *exists) { std::string myKey = key; MakeLowerCase(myKey); FindAndReplace<std::string>(myKey, "\\", "/"); std::string regPath = EnsureTrailingDelimiter(m_StoragePath) + EnsureTrailingDelimiter(myKey) + name; return TortoiseRegistry::ReadString(regPath, defaultValue, exists); }
// Read a vector void TortoiseRegistryCache::ReadVector(const std::string& key, const std::string& prefix, std::vector<std::string>& values) { std::string myKey = key; MakeLowerCase(myKey); FindAndReplace<std::string>(myKey, "\\", "/"); std::string regPath = EnsureTrailingDelimiter(m_StoragePath) + EnsureTrailingDelimiter(myKey) + prefix; TortoiseRegistry::ReadVector(regPath, values); }
// Write a string void TortoiseRegistryCache::WriteString(const std::string& key, const std::string& name, const std::string& value) { // Update LRU list MarkAsUsed(key); std::string myKey = key; MakeLowerCase(myKey); FindAndReplace<std::string>(myKey, "\\", "/"); // Write values std::string regPath = EnsureTrailingDelimiter(m_StoragePath) + EnsureTrailingDelimiter(myKey) + name; TortoiseRegistry::WriteString(regPath, value); }
// Do update ignored list void DoUpdateIgnoredList() { TDEBUG_ENTER("DoUpdateIgnoredList"); defIgnoredList.clear(); defIgnoreListTimeStamp = GetTickCount(); // Default ignored list from cvsnt/src/ignore.c static const char* ign_default = ". .. RCSLOG tags TAGS RCS SCCS .make.state " ".nse_depinfo #* .#* cvslog.* ,* CVS CVS.adm .del-* *.a *.olb *.o *.obj " "*.so *.Z *~ *.old *.elc *.ln *.bak *.orig *.rej _$* *$"; ign_add(ign_default, defIgnoredList); // .cvsignore from homedir std::string homeDir; bool GotHomeDir = GetHomeDirectory(homeDir); if (GotHomeDir) { // Read .cvsignore file from HOME directory. homeDir = EnsureTrailingDelimiter(homeDir); homeDir += ".cvsignore"; ReadIgnoredFile(homeDir, defIgnoredList); } }
std::string CVSStatus::CVSRootForPath(std::string path) { TDEBUG_ENTER("CVSStatus::CVSRootForPath"); TDEBUG_TRACE("path: " << path); // We must be a directory with a CVS dir path = GetDirectoryPart(path); path = EnsureTrailingDelimiter(path); if (!CVSDirectoryHere(path)) { TDEBUG_TRACE("No CVS directory found in " << path); return ""; } std::string root; std::string rootFile = path + "CVS/Root"; std::ifstream in(rootFile.c_str(), std::ios::in); if (!in.good()) { TDEBUG_TRACE("Error opening " << rootFile); return ""; } std::getline(in, root); return root; }
// Update LRU list void TortoiseRegistryCache::MarkAsUsed(const std::string& key) { std::string myKey = key; MakeLowerCase(myKey); FindAndReplace<std::string>(myKey, "\\", "/"); std::string regPath = EnsureTrailingDelimiter(m_StoragePath) + "LRU"; std::vector<std::string> keys; TortoiseRegistry::ReadVector(regPath, keys); std::vector<std::string>::iterator it = keys.begin(); while (it != keys.end()) { if (*it == myKey) { break; } it++; } if (it != keys.end()) { keys.erase(it); } keys.insert(keys.begin(), myKey); TortoiseRegistry::WriteVector(regPath, keys); }
// Get path std::string FileTree::Node::GetPathFrom(const Node* node) const { if (m_Parent == node || m_Parent == 0) { return GetName(); } else { return EnsureTrailingDelimiter(m_Parent->GetPathFrom(node)) + GetName(); } }
// Get path std::string FileTree::Node::GetPath() const { if (m_Parent) { return EnsureTrailingDelimiter(m_Parent->GetPath()) + m_Parent->GetName(); } else { return ""; } }
void BuildIgnoredList(std::vector<std::string> & ignlist, const std::string& path, DWORD *timeStamp, FileChangeParams *fcp) { TDEBUG_ENTER("BuildIgnoredList"); bool doUpdate = false; std::string ignPath(path); ignPath = EnsureTrailingDelimiter(ignPath); ignPath += ".cvsignore"; FileChangeParams myFcp; if (fcp) myFcp = GetFileChangeParams(ignPath); // Update default ignored list BuildDefaultIgnoredList(); if (timeStamp) { if ((*timeStamp != defIgnoreListTimeStamp) || (*timeStamp == 0)) doUpdate = true; } else { doUpdate = true; } // check directory ignored file if (fcp) { if ((fcp->IsNull()) || (*fcp != myFcp)) { doUpdate = true; } } else { doUpdate = true; } // Do we have to update if (doUpdate) { ignlist.clear(); ignlist = defIgnoredList; // TODO: read $CVSROOT/CVSROOT/cvsignore // Read .cvsignore from current directory ReadIgnoredFile(ignPath, ignlist); if (fcp) *fcp = myFcp; if (timeStamp) *timeStamp = defIgnoreListTimeStamp; } }
std::string CVSStatus::CVSRepositoryForPath(std::string path) { TDEBUG_ENTER("CVSStatus::CVSRepositoryForPath"); TDEBUG_TRACE(" path: '" << path << "')"); // We must be a directory with a CVS dir path = GetDirectoryPart(path); path = EnsureTrailingDelimiter(path); if (!CVSDirectoryHere(path)) return ""; std::string rootFile = path + "CVS/Repository"; std::ifstream in(rootFile.c_str(), std::ios::in); if (!in.good()) return ""; std::string repository; std::getline(in, repository); // Apparently, the path in CVS/Repository may be either absolute or relative. // So if it is absolute, we hack it to be relative. TDEBUG_TRACE(" Repository is '" << repository << "')"); if (repository[0] == '/' || (repository.length() > 2 && repository[1] == ':')) { CVSRoot cvsroot(CVSRootForPath(path)); std::string root = cvsroot.GetDirectory(); TDEBUG_TRACE(" Root is '" << root << "')"); unsigned int i = 0; // Find out how many leading chars match while (i < root.length() && i < repository.length()) { if (root[i] == repository[i] || (root[i] == '\\' && repository[i] == '/') || (root[i] == '/' && repository[i] == '\\')) { i++; continue; } else { break; } } // Also kill final slash if (repository[i] == '/' || repository[i] == '\\') ++i; repository = repository.substr(i); } return repository; }
// Build default ignored list void BuildDefaultIgnoredList() { TDEBUG_ENTER("BuildDefaultIgnoredList"); CSHelper csHelper(myCriticalSection, true); std::string userCvsIgnoreFile; GetHomeDirectory(userCvsIgnoreFile); userCvsIgnoreFile = EnsureTrailingDelimiter(userCvsIgnoreFile) + ".cvsignore"; FileChangeParams myFcp = GetFileChangeParams(userCvsIgnoreFile); // Update every dwUpdateIgnoredListInterval seconds if (GetTickCount() > defIgnoreListTimeStamp + 1000 * dwUpdateIgnoredListInterval) { DoUpdateIgnoredList(); fcpCvsignore = myFcp; } // Update if .cvsignore in home dir has changed else if (fcpCvsignore != myFcp) { DoUpdateIgnoredList(); fcpCvsignore = myFcp; } }
// Shrink cache void TortoiseRegistryCache::Shrink() { std::string regPath = EnsureTrailingDelimiter(m_StoragePath) + "LRU"; std::vector<std::string> lruKeys, regKeys; TortoiseRegistry::ReadVector(regPath, lruKeys); if (lruKeys.size() <= m_MaxSize) return; // Remove keys from LRU list while (lruKeys.size() > m_MaxSize) { lruKeys.erase(lruKeys.end() - 1); } // Store keys in map for faster access std::vector<std::string>::iterator it = lruKeys.begin(); std::map<std::string, bool> lruMap; while (it != lruKeys.end()) { lruMap.insert(std::pair<std::string, bool>(*it, true)); it++; } // Remove invalid keys TortoiseRegistry::ReadKeys(m_StoragePath, regKeys); std::string myKey; while (it != regKeys.end()) { myKey = *it; MakeLowerCase(myKey); if (lruMap.find(myKey) == lruMap.end()) { TortoiseRegistry::EraseKey(myKey); } it++; } }
EntnodeData *Entries_SetVisited(const char* path, EntnodeMap& entries, const char* name, const struct stat& finfo, bool isDir, bool isReadOnly, bool isMissing, const std::vector<std::string>* ignlist) { TDEBUG_ENTER("Entries_SetVisited"); bool isCvs = false; std::string lookupName; if (isDir) { TDEBUG_TRACE("Is dir"); EntnodeDir *adata = new EntnodeDir(path, name); ENTNODE anode(adata); adata->UnRef(); lookupName = anode.Data()->GetName(); EntnodeMap::iterator it = entries.find(lookupName); isCvs = it != entries.end(); if (!isCvs) entries[lookupName] = anode; } else { TDEBUG_TRACE("Is no dir"); EntnodeFile *adata = new EntnodeFile(path, name); ENTNODE anode(adata); adata->UnRef(); lookupName = anode.Data()->GetName(); EntnodeMap::iterator it = entries.find(lookupName); isCvs = it != entries.end(); if (!isCvs) entries[lookupName] = anode; } const ENTNODE & theNode = entries[lookupName]; EntnodeData *data = ((ENTNODE *)&theNode)->Data(); data->SetVisited(true); if (!isCvs) { data->SetUnknown(true); if (ignlist && MatchIgnoredList(name, *ignlist) || finfo.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) data->SetIgnored(true); // the dir may have some cvs informations in it, despite the fact // that it is not referenced by the parent directory, so try // to figure it. if (!data->IsIgnored()) { std::string cvsFile = path; cvsFile = EnsureTrailingDelimiter(cvsFile); cvsFile += name; cvsFile = EnsureTrailingDelimiter(cvsFile); cvsFile += "CVS"; struct stat sb; TDEBUG_TRACE("Before stat"); if (stat(cvsFile.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) { data->SetUnknown(false); } TDEBUG_TRACE("After stat"); } } data->SetReadOnly(isReadOnly); data->SetMissing(isMissing); if (isDir) { if (data->IsIgnored()) data->SetDesc(_("Ignored Folder")); else if (data->IsUnknown()) data->SetDesc(_("Non-CVS Folder")); else data->SetDesc(_("Folder")); } else if (!isMissing) { const char* ts = data->GetTS(); TDEBUG_TRACE("Timestamp: " << (ts == 0 ? "NULL" : ts)); // Revision "0" means "added" if (ts == 0) { data->SetUnmodified(true); } else if (strcmp(data->GetVN(), "0") == 0) { data->SetAdded(true); // Added files are always modified data->SetUnmodified(false); } else { data->SetUnmodified(unmodified(finfo, ts)); } const char* ts_conflict = data->GetConflict(); if (ts_conflict == 0) data->SetNeedsMerge(false); else data->SetNeedsMerge(unmodified(finfo,ts_conflict)); data->SetLocked((finfo.st_mode & S_IWRITE) == 0); const char* info = 0; if (data->IsIgnored()) { data->SetDesc(_("Ignored")); } else if (data->IsUnknown()) { data->SetDesc(_("Non-CVS File")); } else if (data->NeedsMerge()) { data->SetDesc(_("Conflict")); } else if ((info = data->GetOption()) != 0 && strcmp(info, "-kb") == 0) { data->SetDesc(data->IsUnmodified() ? _("Binary") : _("Mod. Binary")); } else { data->SetDesc(data->IsUnmodified() ? _("File") : _("Mod. File")); } } return data; }
/* Read the entries file into a list, hashing on the file name. UPDATE_DIR is the name of the current directory, for use in error messages, or NULL if not known (that is, noone has gotten around to updating the caller to pass in the information). */ bool Entries_Open(EntnodeMap& entries, const char* fullpath, FileChangeParams* fcp) { TDEBUG_ENTER("Entries_Open"); std::string cvsdir(fullpath); cvsdir = EnsureTrailingDelimiter(cvsdir); cvsdir += "CVS"; cvsdir = EnsureTrailingDelimiter(cvsdir); if (fcp) { FileChangeParams myFcp = GetFileChangeParams(cvsdir + "Entries"); if ((!(fcp->IsNull())) && (myFcp == *fcp)) { return true; } *fcp = myFcp; } entries.clear(); unsigned long sizeextra = 0; FILE* fpinx = fopen((cvsdir + "Entries.Extra").c_str(), "r"); if (fpinx) { FileChangeParams myFcp = GetFileChangeParams(cvsdir + "Entries.Extra"); sizeextra = myFcp.dwFileSizeLow; } FILE* fpin = fopen((cvsdir + "Entries").c_str(), "r"); if (!fpin) { if (fpinx) fclose (fpinx); return false; } // Read contents of CVS/Rename into a set for easy lookup std::ifstream cvsRename((cvsdir + "Rename").c_str()); std::set<std::string> renameEntries; while (cvsRename.good()) { std::string file; // Each entry is // newname // (blank) // newname // oldname // We are only interested in the new name. std::getline(cvsRename, file); file = ExtractLastPart(file); renameEntries.insert(file); for (int i = 0; i < 3; ++i) std::getline(cvsRename, file); } EntnodeData* ent; char* extrabuf = 0; size_t lenreadx; if (fpinx && (sizeextra > 0)) { extrabuf = (char*) malloc((sizeextra*2)+10); fseek(fpinx, 0, SEEK_SET); lenreadx = fread(extrabuf, sizeof(char), (sizeextra*2)+9, fpinx); *(extrabuf+lenreadx) = '\0'; if (!feof(fpinx)) { // could not read the whole file for some reason... free(extrabuf); extrabuf = 0; } } while ((ent = fgetentent(fpin, extrabuf, fullpath, 0, sizeextra)) != 0) { ENTNODE newnode(ent); ent->UnRef(); std::string name = newnode.Data()->GetName(); EntnodeMap::iterator it = entries.find(name); if (it != entries.end()) { _ASSERT(false); TDEBUG_TRACE("Warning : duplicated entry in the 'CVS/Entries' file in folder " << fullpath); } std::set<std::string>::iterator renameIter = renameEntries.find(name); ent->SetRenamed(renameIter != renameEntries.end()); entries[name] = newnode; } fclose (fpin); if (fpinx) fclose (fpinx); if (extrabuf) free (extrabuf); fpin = fopen((cvsdir + "Entries.log").c_str(), "r"); if (fpin) { char cmd; while ((ent = fgetentent(fpin, extrabuf, fullpath, &cmd, sizeextra)) != 0) { ENTNODE newnode(ent); ent->UnRef(); std::string name = newnode.Data()->GetName(); switch (cmd) { case 'A': entries[name] = newnode; break; case 'R': entries.erase(std::string(name)); break; default: /* Ignore unrecognized commands. */ TDEBUG_TRACE("Warning: Unrecognized command '" << cmd << "'"); break; } } fclose (fpin); } return true; }
// Get full name std::string FileTree::Node::GetFullName() const { return EnsureTrailingDelimiter(this->GetPath()) + GetName(); }
// View a revision bool DoView(DirectoryGroups& dirGroups, std::string rev) { std::string dir = UniqueTemporaryDir(); std::string viewFile = dir; bool ok = true; CVSAction glue(0); std::string cvsroot; bool unixSandbox = IsUnixSandbox(StripLastPart(dirGroups.mySingleAbsolute)); if (!rev.empty()) { viewFile += "\\" + MakeRevFilename(ExtractLastPart(dirGroups.mySingleAbsolute), rev); DeleteFileA(viewFile.c_str()); } glue.SetProgressFinishedCaption(Printf(_("Viewing %s"), wxText(dirGroups.mySingleAbsolute).c_str())); glue.SetProgressCaption(Printf(_("Viewing %s"), wxText(dirGroups.mySingleAbsolute).c_str())); cvsroot = CVSStatus::CVSRootForPath(dirGroups.mySingleDirectory); // Viewing revision if (!rev.empty()) { glue.SetCVSRoot(CVSRoot(cvsroot)); MakeArgs args; std::string sTempDir = UniqueTemporaryDir(); glue.SetCloseIfOK(true); args.add_option("checkout"); if (unixSandbox) { CVSServerFeatures sf; sf.Initialize(&glue); sf.AddUnixLineEndingsFlag(args); } if (rev != "HEAD") { args.add_option("-r"); args.add_option(rev); } args.add_option("-d"); args.add_option("temp"); std::string s = EnsureTrailingUnixDelimiter(CVSStatus::CVSRepositoryForPath(dirGroups.mySingleAbsolute)) + ExtractLastPart(dirGroups.mySingleAbsolute); args.add_arg(s); ok = glue.Command(sTempDir, args); if (ok) { // Copy file to destination std::string file = EnsureTrailingDelimiter(sTempDir) + "temp\\" + ExtractLastPart(dirGroups.mySingleAbsolute); SetFileReadOnly(file.c_str(), false); CopyFileA(file.c_str(), viewFile.c_str(), false); SetFileReadOnly(viewFile.c_str(), true); } // Erase temporary directory DeleteDirectoryRec(sTempDir); if (!ok) goto Cleanup; } if (!FileExists(viewFile.c_str())) { DoMessageDialog(0, wxString(_("This file is new and has never been committed to the server or is an empty file on the server.")) + wxString(wxT("\n\n")) + wxString(wxText(dirGroups.mySingleAbsolute))); return true; } // Perform view, waiting for it to finish (so we can delete file) glue.LockProgressDialog(true); if (rev.empty()) LaunchFile(dirGroups.mySingleAbsolute, true); else LaunchFile(viewFile, true); glue.LockProgressDialog(false); Cleanup: // Clean up if (!rev.empty()) { SetFileReadOnly(viewFile.c_str(), false); DeleteFileA(viewFile.c_str()); } DeleteDirectoryRec(dir); return ok; }
bool DoDiff(DirectoryGroups& dirGroups, std::string rev1, std::string rev2, bool forceQuery) { std::string dir = UniqueTemporaryDir(); AutoDirectoryDeleter dirDeleter(dir); std::string diffFile = dir; std::string diffFile2 = diffFile; bool ok = true; CVSAction glue(0); if (rev1.empty()) rev1 = CVSStatus::GetRevisionNumber(dirGroups.mySingleAbsolute); // Should we do a text diff only? std::string externalApp = GetExternalApplication("Diff", dirGroups, forceQuery); forceQuery = false; if (externalApp.empty()) { // Perform a textual diff glue.SetProgressFinishedCaption(Printf(_("Finished diff in %s"), wxText(dirGroups.mySingleDirectory).c_str())); glue.SetProgressCaption(Printf(_("Diffing in %s"), wxText(dirGroups.mySingleDirectory).c_str())); MakeArgs args; args.add_option("diff"); args.add_option("-u"); args.add_option("-r"); args.add_option(rev1); if (!rev2.empty()) { args.add_option("-r"); args.add_option(rev2); } args.add_arg(dirGroups.mySingleRelative); return glue.Command(dirGroups.mySingleDirectory, args); } bool unixSandbox = IsUnixSandbox(StripLastPart(dirGroups.mySingleAbsolute)); diffFile += "\\" + MakeRevFilename(ExtractLastPart(dirGroups.mySingleAbsolute), rev1); DeleteFileA(diffFile.c_str()); AutoFileDeleter diffFileDeleter(diffFile); AutoFileDeleter diffFile2Deleter; if (!rev2.empty()) { diffFile2 += "\\" + MakeRevFilename(ExtractLastPart(dirGroups.mySingleAbsolute), rev2); DeleteFileA(diffFile2.c_str()); diffFile2Deleter.Attach(diffFile2); } glue.SetProgressFinishedCaption(Printf(_("Finished diff in %s"), wxText(dirGroups.mySingleDirectory).c_str())); glue.SetProgressCaption(Printf(_("Diffing in %s"), wxText(dirGroups.mySingleDirectory).c_str())); std::string cvsroot = CVSStatus::CVSRootForPath(dirGroups.mySingleDirectory); CVSServerFeatures sf; if (unixSandbox) sf.Initialize(&glue); // Diffing two revisions if (!rev1.empty()) { glue.SetCVSRoot(CVSRoot(cvsroot)); MakeArgs args; std::string tempDir = UniqueTemporaryDir(); glue.SetCloseIfOK(true); args.add_global_option("-f"); args.add_option("checkout"); if (rev1 != "HEAD") { args.add_option("-r"); args.add_option(rev1); } args.add_option("-d"); args.add_option("temp"); if (unixSandbox) sf.AddUnixLineEndingsFlag(args); std::string s = EnsureTrailingUnixDelimiter(CVSStatus::CVSRepositoryForPath(dirGroups.mySingleAbsolute)) + ExtractLastPart(dirGroups.mySingleAbsolute); args.add_arg(s); ok = glue.Command(tempDir, args); if (ok) { // Copy file to destination std::string file = EnsureTrailingDelimiter(tempDir) + "temp\\" + ExtractLastPart(dirGroups.mySingleAbsolute); SetFileReadOnly(file.c_str(), false); CopyFileA(file.c_str(), diffFile.c_str(), false); SetFileReadOnly(diffFile.c_str(), true); } // Erase temporary directory DeleteDirectoryRec(tempDir); if (!ok) return false; glue.CloseConsoleOutput(); } if (!rev2.empty()) { glue.SetCVSRoot(CVSRoot(cvsroot)); MakeArgs args; std::string tempDir = UniqueTemporaryDir(); glue.SetCloseIfOK(true); args.add_global_option("-f"); args.add_option("checkout"); args.add_option("-r"); args.add_option(rev2); args.add_option("-d"); args.add_option("temp"); if (unixSandbox) sf.AddUnixLineEndingsFlag(args); std::string s = EnsureTrailingUnixDelimiter(CVSStatus::CVSRepositoryForPath(dirGroups.mySingleAbsolute)) + ExtractLastPart(dirGroups.mySingleAbsolute); args.add_arg(s); ok = glue.Command(tempDir, args); if (ok) { // Copy file to destination std::string file = EnsureTrailingDelimiter(tempDir) + "temp\\" + ExtractLastPart(dirGroups.mySingleAbsolute); SetFileReadOnly(file.c_str(), false); CopyFileA(file.c_str(), diffFile2.c_str(), false); SetFileReadOnly(diffFile2.c_str(), true); } // Erase temporary directory DeleteDirectoryRec(tempDir); if (!ok) return false; glue.CloseConsoleOutput(); } if (!FileExists(diffFile.c_str())) { DoMessageDialog(0, wxString(_("This file is new and has never been committed to the server or is an empty file on the server.")) + wxString(wxT("\n\n")) + wxString(wxText(dirGroups.mySingleAbsolute))); return true; } do { externalApp = GetExternalApplication("Diff", dirGroups, forceQuery); forceQuery = false; if (externalApp.empty()) { return false; } // Perform diff, waiting for it to finish (so we can delete file) glue.LockProgressDialog(true); if (rev2.empty()) forceQuery = !RunExternalDiff(diffFile, dirGroups.mySingleAbsolute, dirGroups); else forceQuery = !RunExternalDiff(diffFile, diffFile2, dirGroups); glue.LockProgressDialog(false); } while (forceQuery); return true; }