def last_rev(svnrepos, path, peg_revision, limit_revision=None): """Given PATH, known to exist in PEG_REVISION, find the youngest revision older than, or equal to, LIMIT_REVISION in which path exists. Return that revision, and the path at which PATH exists in that revision.""" # Here's the plan, man. In the trivial case (where PEG_REVISION is # the same as LIMIT_REVISION), this is a no-brainer. If # LIMIT_REVISION is older than PEG_REVISION, we can use Subversion's # history tracing code to find the right location. If, however, # LIMIT_REVISION is younger than PEG_REVISION, we suffer from # Subversion's lack of forward history searching. Our workaround, # ugly as it may be, involves a binary search through the revisions # between PEG_REVISION and LIMIT_REVISION to find our last live # revision. peg_revision = svnrepos._getrev(peg_revision) limit_revision = svnrepos._getrev(limit_revision) try: if peg_revision == limit_revision: return peg_revision, path elif peg_revision > limit_revision: fsroot = svnrepos._getroot(peg_revision) history = fs.node_history(fsroot, path, svnrepos.scratch_pool) while history: path, peg_revision = fs.history_location( history, svnrepos.scratch_pool) if peg_revision <= limit_revision: return max(peg_revision, limit_revision), _cleanup_path(path) history = fs.history_prev(history, 1, svnrepos.scratch_pool) return peg_revision, _cleanup_path(path) else: ### Warning: this is *not* an example of good pool usage. orig_id = fs.node_id(svnrepos._getroot(peg_revision), path, svnrepos.scratch_pool) while peg_revision != limit_revision: mid = (peg_revision + 1 + limit_revision) / 2 try: mid_id = fs.node_id(svnrepos._getroot(mid), path, svnrepos.scratch_pool) except core.SubversionException, e: if e.apr_err == core.SVN_ERR_FS_NOT_FOUND: cmp = -1 else: raise else: ### Not quite right. Need a comparison function that only returns ### true when the two nodes are the same copy, not just related. cmp = fs.compare_ids(orig_id, mid_id) if cmp in (0, 1): peg_revision = mid else: limit_revision = mid - 1 return peg_revision, path finally: svnrepos._scratch_clear()
def last_rev(svnrepos, path, peg_revision, limit_revision=None): """Given PATH, known to exist in PEG_REVISION, find the youngest revision older than, or equal to, LIMIT_REVISION in which path exists. Return that revision, and the path at which PATH exists in that revision.""" # Here's the plan, man. In the trivial case (where PEG_REVISION is # the same as LIMIT_REVISION), this is a no-brainer. If # LIMIT_REVISION is older than PEG_REVISION, we can use Subversion's # history tracing code to find the right location. If, however, # LIMIT_REVISION is younger than PEG_REVISION, we suffer from # Subversion's lack of forward history searching. Our workaround, # ugly as it may be, involves a binary search through the revisions # between PEG_REVISION and LIMIT_REVISION to find our last live # revision. peg_revision = svnrepos._getrev(peg_revision) limit_revision = svnrepos._getrev(limit_revision) try: if peg_revision == limit_revision: return peg_revision, path elif peg_revision > limit_revision: fsroot = svnrepos._getroot(peg_revision) history = fs.node_history(fsroot, path, svnrepos.scratch_pool) while history: path, peg_revision = fs.history_location(history, svnrepos.scratch_pool); if peg_revision <= limit_revision: return max(peg_revision, limit_revision), _cleanup_path(path) history = fs.history_prev(history, 1, svnrepos.scratch_pool) return peg_revision, _cleanup_path(path) else: ### Warning: this is *not* an example of good pool usage. orig_id = fs.node_id(svnrepos._getroot(peg_revision), path, svnrepos.scratch_pool) while peg_revision != limit_revision: mid = (peg_revision + 1 + limit_revision) / 2 try: mid_id = fs.node_id(svnrepos._getroot(mid), path, svnrepos.scratch_pool) except core.SubversionException, e: if e.apr_err == core.SVN_ERR_FS_NOT_FOUND: cmp = -1 else: raise else: ### Not quite right. Need a comparison function that only returns ### true when the two nodes are the same copy, not just related. cmp = fs.compare_ids(orig_id, mid_id) if cmp in (0, 1): peg_revision = mid else: limit_revision = mid - 1 return peg_revision, path finally: svnrepos._scratch_clear()