Changeset 70fef26106da…
Parent 6c34798f128d…
by
Changes to 4 files · Browse files at 70fef26106da Showing diff from parent 6c34798f128d Diff from another changeset...
|
@@ -0,0 +1,69 @@ + # thgstatus.py - TortoiseHg status cache extension for Mercurial
+#
+# Copyright (C) 2009 Adrian Buehlmann
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from mercurial.i18n import _
+from mercurial import commands
+
+def cachefilepath(repo):
+ return repo.root + "/.hg/thgstatus"
+
+def dirname(f):
+ return '/'.join(f.split('/')[:-1])
+
+def thgstatus(ui, repo, source='default', **opts):
+ '''update directory status cache for TortoiseHg
+
+ Caches the information provided by 'hg status' in the file .hg/thgstatus
+ which can then be used by the TortoiseHg shell extension to display
+ overlay icons for directories.
+ The file .hg/thgstatus contains one line for each directory that has
+ removed, modified or added files (in that order of preference). Each line
+ consists of one char for the status of the directory (r, m or a), followed
+ by the relative path of the directory in the repo.
+ If the file is empty, then the repo is clean.
+ '''
+
+ repostate = repo.status()
+ modified, added, removed, deleted, unknown, ignored, clean = repostate
+ dirstatus = {}
+ for fn in added:
+ dirstatus[dirname(fn)] = 'a'
+ for fn in modified:
+ dirstatus[dirname(fn)] = 'm'
+ for fn in removed:
+ dirstatus[dirname(fn)] = 'r'
+ nmodified, nadded, nremoved = 0, 0, 0
+ f = open(cachefilepath(repo), 'wb')
+ for dn in sorted(dirstatus):
+ s = dirstatus[dn]
+ if (s == 'm'):
+ nmodified += 1
+ elif (s == 'a'):
+ nadded += 1
+ elif (s == 'r'):
+ nremoved +=1
+ f.write(dirstatus[dn] + dn + '\n')
+ f.close()
+ ui.status(_("updated cached directory status: "
+ "%i modified, %i added, %i removed") % (nmodified, nadded, nremoved))
+
+cmdtable = {
+ 'thgstatus':
+ (thgstatus,
+ [ ],
+ _('hg thgstatus')),
+}
|
|
@@ -24,7 +24,7 @@ Directory::Directory(
Directory* p, const std::string& n, const std::string& basepath
):
- parent_(p), name_(n), tickcount_(0), status_(-1)
+ parent_(p), name_(n)
{
if (n.empty())
path_ = basepath;
@@ -201,73 +201,6 @@}
-char Directory::status_imp(const std::string& hgroot)
-{
- bool added = false;
-
- std::vector<Directory*> todo;
- todo.push_back(this);
-
- Winstat stat;
- std::string basepath;
-
- while (!todo.empty())
- {
- Directory* const d = todo.back();
- todo.pop_back();
-
- //TDEBUG_TRACE("Directory(" << path() << ")::status_imp: "
- // "popped '" << d->path() << "'");
-
- if (!d->files_.empty())
- {
- basepath = hgroot + "/" + d->path() + "/";
-
- for (FilesT::iterator i = d->files_.begin(); i != d->files_.end(); ++i)
- {
- if (i->state == 'r')
- return 'M'; // file was removed, report dir as modified
-
- std::string p = basepath + i->name;
- if (0 != stat.lstat(p.c_str()))
- return 'M'; // file is missing, report dir as modified
-
- char s = i->status(stat);
-
- if (s == 'M')
- return 'M';
- if (s == 'A')
- added = true;
- }
- }
-
- todo.insert(todo.end(), d->subdirs_.begin(), d->subdirs_.end());
- }
-
- if (added)
- return 'A';
-
- return 'C';
-}
-
-
-char Directory::status(const std::string& hgroot)
-{
- if (status_ != -1)
- {
- unsigned tc = GetTickCount();
- if (tc - tickcount_ < 3000) {
- return status_;
- }
- }
-
- status_ = status_imp(hgroot);
- tickcount_ = GetTickCount();
-
- return status_;
-}
-
-
void Directory::print() const
{
for (DirsT::const_iterator i = subdirs_.begin(); i != subdirs_.end(); ++i)
|
@@ -35,9 +35,6 @@
DirsT subdirs_;
FilesT files_;
-
- unsigned tickcount_;
- char status_;
public:
Directory(Directory* p, const std::string& n, const std::string& basepath);
@@ -50,12 +47,7 @@ const Direntry* get(const std::string& relpath) const;
Directory* Directory::getdir(const std::string& n);
- char status(const std::string& hgroot);
-
void print() const;
-
-private:
- char status_imp(const std::string& hgroot);
};
#endif
|
|
@@ -89,30 +89,140 @@ }
+class DirectoryStatus
+{
+ struct E
+ {
+ std::string path_;
+ char status_;
+
+ E(): status_(0) {}
+ };
+
+ typedef std::vector<E> V;
+ V v_;
+
+public:
+ int read(const std::string& hgroot);
+ char status(const std::string& relpath) const;
+};
+
+
+char DirectoryStatus::status(const std::string& relpath) const
+{
+ TDEBUG_TRACE("DirectoryStatus::status(" << relpath << ")");
+
+ char res = 'C';
+ bool added = false;
+ bool modified = false;
+
+ for (V::const_iterator i = v_.begin(); i != v_.end(); ++i)
+ {
+ const E& e = *i;
+ if (e.path_.compare(0, relpath.length(), relpath) == 0)
+ {
+ TDEBUG_TRACE("DirectoryStatus::status(" << relpath << "):"
+ << " found '" << e.path_ << "'");
+ if (e.status_ == 'r' || e.status_ == 'm')
+ {
+ modified = true;
+ break;
+ }
+ if (e.status_ == 'a')
+ added = true;
+ }
+ }
+
+ if (modified)
+ res = 'M';
+ else if (added)
+ res = 'A';
+ else
+ res = 'C';
+
+ TDEBUG_TRACE("DirectoryStatus::status(" << relpath << "): returns " << res);
+ return res;
+}
+
+
+int DirectoryStatus::read(const std::string& hgroot)
+{
+ v_.clear();
+
+ std::string p = hgroot + "\\.hg\\thgstatus";
+
+ FILE *f = fopen(p.c_str(), "rb");
+ if (!f)
+ {
+ TDEBUG_TRACE("DirectoryStatus::read: can't open " << p);
+ return 0;
+ }
+
+ char state;
+ std::vector<char> path(MAX_PATH);
+
+ DirectoryStatus::E e;
+
+ while (fread(&state, sizeof(state), 1, f) == 1)
+ {
+ e.status_ = state;
+
+ path.clear();
+ char t;
+ while (fread(&t, sizeof(t), 1, f) == 1 && t != '\n')
+ {
+ path.push_back(t);
+ if (path.size() > 1000)
+ return 0;
+ }
+ path.push_back(0);
+
+ e.path_ = &path[0];
+
+ v_.push_back(e);
+ }
+
+ fclose(f);
+
+ TDEBUG_TRACE("DirectoryStatus::read(" << hgroot << "): done. "
+ << v_.size() << " entries read");
+
+ return 1;
+}
+
+
class Dirstatecache
{
- struct entry
+ struct E
{
Dirstate* dstate;
- __time64_t mtime;
+ __time64_t dstate_mtime;
+
+ DirectoryStatus* tstate;
+ __time64_t tstate_mtime;
+
std::string hgroot;
unsigned tickcount;
- entry(): dstate(0), mtime(0), tickcount(0) {}
+ E()
+ : dstate(0), dstate_mtime(0),
+ tstate(0), tstate_mtime(0), tickcount(0) {}
};
- typedef std::list<entry>::iterator Iter;
+ typedef std::list<E>::iterator Iter;
- static std::list<entry> _cache;
+ static std::list<E> _cache;
public:
- static Dirstate* get(const std::string& hgroot);
+ static int get(const std::string& hgroot,
+ Dirstate*& outDirstate, DirectoryStatus*& outDirectoryStatus);
};
-std::list<Dirstatecache::entry> Dirstatecache::_cache;
+std::list<Dirstatecache::E> Dirstatecache::_cache;
-Dirstate* Dirstatecache::get(const std::string& hgroot)
+int Dirstatecache::get(const std::string& hgroot,
+ Dirstate*& outDirstate, DirectoryStatus*& outDirectoryStatus)
{
Iter iter = _cache.begin();
@@ -133,7 +243,7 @@ _cache.back().dstate = 0;
_cache.pop_back();
}
- entry e;
+ E e;
e.hgroot = hgroot;
_cache.push_front(e);
iter = _cache.begin();
@@ -160,9 +270,9 @@ TDEBUG_TRACE("Dirstatecache::get: lstat(" << path <<") ok ");
}
- if (stat_done && iter->mtime < stat.mtime)
+ if (stat_done && iter->dstate_mtime < stat.mtime)
{
- iter->mtime = stat.mtime;
+ iter->dstate_mtime = stat.mtime;
if (iter->dstate) {
delete iter->dstate;
iter->dstate = 0;
@@ -178,7 +288,19 @@ << _cache.size() << " repos in cache");
}
- return iter->dstate;
+ delete iter->tstate;
+ iter->tstate = 0;
+
+ {
+ std::auto_ptr<DirectoryStatus> pds(new DirectoryStatus());
+ if (pds->read(hgroot))
+ iter->tstate = pds.release();
+ }
+
+ outDirstate = iter->dstate;
+ outDirectoryStatus = iter->tstate;
+
+ return 1;
}
@@ -212,10 +334,13 @@ || (relpath.size() > 4 && relpath.compare(0, 4, ".hg/") == 0))
return 0; // don't descend into .hg dir
- Dirstate* pds = Dirstatecache::get(hgroot);
+ Dirstate* pds = 0;
+ DirectoryStatus* pts = 0;
+ Dirstatecache::get(hgroot, pds, pts);
if (!pds)
{
- TDEBUG_TRACE("HgQueryDirstate: Dirstatecache::get(" << hgroot << ") returns 0");
+ TDEBUG_TRACE("HgQueryDirstate: Dirstatecache::get("
+ << hgroot << ") returns no Dirstate");
return 0;
}
@@ -224,10 +349,10 @@
if (PathIsDirectory(path.c_str()))
{
- Directory* dir = pds->root().getdir(relpath);
- if (!dir)
+ if (!pts)
return 0;
- outStatus = dir->status(hgroot);
+
+ outStatus = pts->status(relpath);
}
else
{
|
Loading...