def _get_dirents(self, path, rev): """Return a 2-type of dirents and locks, possibly reading/writing from a local cache of that information. This functions performs authz checks, stripping out unreadable dirents.""" dir_url = self._geturl(path) path_parts = _path_parts(path) if path: key = str(rev) + '/' + path else: key = str(rev) # Ensure that the cache gets filled... dirents_locks = self._dirent_cache.get(key) if not dirents_locks: tmp_dirents, locks = list_directory(dir_url, _rev2optrev(rev), _rev2optrev(rev), 0, self.ctx) dirents = {} for name, dirent in tmp_dirents.items(): dirent_parts = path_parts + [name] kind = dirent.kind if (kind == core.svn_node_dir or kind == core.svn_node_file) \ and vclib.check_path_access(self, dirent_parts, kind == core.svn_node_dir \ and vclib.DIR or vclib.FILE, rev): lh_rev, c_rev = self._get_last_history_rev(dirent_parts, rev) dirent.created_rev = lh_rev dirents[name] = dirent dirents_locks = [dirents, locks] self._dirent_cache[key] = dirents_locks # ...then return the goodies from the cache. return dirents_locks[0], dirents_locks[1]
def itemprops(self, path_parts, rev): path = self._getpath(path_parts) path_type = self.itemtype(path_parts, rev) # does auth-check rev = self._getrev(rev) url = self._geturl(path) pairs = client.svn_client_proplist2(url, _rev2optrev(rev), _rev2optrev(rev), 0, self.ctx) return pairs and pairs[0][1] or {}
def _get_last_history_rev(self, path_parts, rev): """Return the a 2-tuple which contains: - the last interesting revision equal to or older than REV in the history of PATH_PARTS. - the created_rev of of PATH_PARTS as of REV.""" path = self._getpath(path_parts) url = self._geturl(self._getpath(path_parts)) optrev = _rev2optrev(rev) # Get the last-changed-rev. revisions = [] def _info_cb(path, info, pool, retval=revisions): revisions.append(info.last_changed_rev) client.svn_client_info(url, optrev, optrev, _info_cb, 0, self.ctx) last_changed_rev = revisions[0] # Now, this object might not have been directly edited since the # last-changed-rev, but it might have been the child of a copy. # To determine this, we'll run a potentially no-op log between # LAST_CHANGED_REV and REV. lc = LogCollector(path, 1, None, None) client_log(url, optrev, _rev2optrev(last_changed_rev), 1, 1, 0, lc.add_log, self.ctx) revs = lc.logs if revs: revs.sort() return revs[0].number, last_changed_rev else: return last_changed_rev, last_changed_rev
def _get_dirents(self, path, rev): """Return a 2-type of dirents and locks, possibly reading/writing from a local cache of that information. This functions performs authz checks, stripping out unreadable dirents.""" dir_url = self._geturl(path) path_parts = _path_parts(path) if path: key = str(rev) + '/' + path else: key = str(rev) # Ensure that the cache gets filled... dirents_locks = self._dirent_cache.get(key) if not dirents_locks: tmp_dirents, locks = list_directory(dir_url, _rev2optrev(rev), _rev2optrev(rev), 0, self.ctx) dirents = {} for name, dirent in tmp_dirents.items(): dirent_parts = path_parts + [name] kind = dirent.kind if (kind == core.svn_node_dir or kind == core.svn_node_file) \ and vclib.check_path_access(self, dirent_parts, kind == core.svn_node_dir \ and vclib.DIR or vclib.FILE, rev): lh_rev, c_rev = self._get_last_history_rev( dirent_parts, rev) dirent.created_rev = lh_rev dirents[name] = dirent dirents_locks = [dirents, locks] self._dirent_cache[key] = dirents_locks # ...then return the goodies from the cache. return dirents_locks[0], dirents_locks[1]
def annotate(self, path_parts, rev): path = self._getpath(path_parts) if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check raise vclib.Error("Path '%s' is not a file." % path) rev = self._getrev(rev) url = self._geturl(path) blame_data = [] def _blame_cb(line_no, revision, author, date, line, pool, blame_data=blame_data): prev_rev = None if revision > 1: prev_rev = revision - 1 blame_data.append( vclib.Annotation(line, line_no + 1, revision, prev_rev, author, None)) client.svn_client_blame(url, _rev2optrev(1), _rev2optrev(rev), _blame_cb, self.ctx) return blame_data, rev
def get_symlink_target(self, path_parts, rev): """Return the target of the symbolic link versioned at PATH_PARTS in REV, or None if that object is not a symlink.""" path = self._getpath(path_parts) path_type = self.itemtype(path_parts, rev) # does auth-check rev = self._getrev(rev) url = self._geturl(path) # Symlinks must be files with the svn:special property set on them # and with file contents which read "link SOME_PATH". if path_type != vclib.FILE: return None pairs = client.svn_client_proplist2(url, _rev2optrev(rev), _rev2optrev(rev), 0, self.ctx) props = pairs and pairs[0][1] or {} if not props.has_key(core.SVN_PROP_SPECIAL): return None pathspec = '' ### FIXME: We're being a touch sloppy here, first by grabbing the ### whole file and then by checking only the first line ### of it. fp = SelfCleanFP(cat_to_tempfile(self, path, rev)) pathspec = fp.readline() fp.close() if pathspec[:5] != 'link ': return None return pathspec[5:]
def itemlog(self, path_parts, rev, sortby, first, limit, options): assert sortby == vclib.SORTBY_DEFAULT or sortby == vclib.SORTBY_REV path_type = self.itemtype(path_parts, rev) # does auth-check path = self._getpath(path_parts) rev = self._getrev(rev) url = self._geturl(path) # If this is a file, fetch the lock status and size (as of REV) # for this item. lockinfo = size_in_rev = None if path_type == vclib.FILE: basename = path_parts[-1] list_url = self._geturl(self._getpath(path_parts[:-1])) dirents, locks = list_directory(list_url, _rev2optrev(rev), _rev2optrev(rev), 0, self.ctx) if locks.has_key(basename): lockinfo = locks[basename].owner if dirents.has_key(basename): size_in_rev = dirents[basename].size # Special handling for the 'svn_latest_log' scenario. ### FIXME: Don't like this hack. We should just introduce ### something more direct in the vclib API. if options.get("svn_latest_log", 0): dir_lh_rev, dir_c_rev = self._get_last_history_rev(path_parts, rev) date, author, log, revprops, changes = self._revinfo(dir_lh_rev) return [vclib.Revision(dir_lh_rev, str(dir_lh_rev), date, author, None, log, size_in_rev, lockinfo)] def _access_checker(check_path, check_rev): return vclib.check_path_access(self, _path_parts(check_path), path_type, check_rev) # It's okay if we're told to not show all logs on a file -- all # the revisions should match correctly anyway. lc = LogCollector(path, options.get("svn_show_all_dir_logs", 0), lockinfo, _access_checker) cross_copies = options.get("svn_cross_copies", 0) log_limit = 0 if limit: log_limit = first + limit client_log(url, _rev2optrev(rev), _rev2optrev(1), log_limit, 1, cross_copies, lc.add_log, self.ctx) revs = lc.logs revs.sort() prev = None for rev in revs: # Swap out revision info with stuff from the cache (which is # authz-sanitized). rev.date, rev.author, rev.log, revprops, changes = self._revinfo(rev.number) rev.prev = prev prev = rev revs.reverse() if len(revs) < first: return [] if limit: return revs[first : first + limit] return revs
def annotate(self, path_parts, rev, include_text=False): path = self._getpath(path_parts) if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check raise vclib.Error("Path '%s' is not a file." % path) rev = self._getrev(rev) url = self._geturl(path) # Examine logs for the file to determine the oldest revision we are # permitted to see. log_options = { 'svn_cross_copies': 1, 'svn_show_all_dir_logs': 1, } revs = self.itemlog(path_parts, rev, vclib.SORTBY_REV, 0, 0, log_options) oldest_rev = revs[-1].number # Now calculate the annotation data. Note that we'll not # inherently trust the provided author and date, because authz # rules might necessitate that we strip that information out. blame_data = [] def _blame_cb(line_no, revision, author, date, line, pool, blame_data=blame_data): prev_rev = None if revision > 1: prev_rev = revision - 1 # If we have an invalid revision, clear the date and author # values. Otherwise, if we have authz filtering to do, use the # revinfo cache to do so. if revision < 0: date = author = None elif self.auth: date, author, msg, revprops, changes = self._revinfo(revision) # Strip text if the caller doesn't want it. if not include_text: line = None blame_data.append( vclib.Annotation(line, line_no + 1, revision, prev_rev, author, date)) client.blame2(url, _rev2optrev(rev), _rev2optrev(oldest_rev), _rev2optrev(rev), _blame_cb, self.ctx) return blame_data, rev
def _get_dirents(self, path, rev): """Return a 2-type of dirents and locks, possibly reading/writing from a local cache of that information.""" dir_url = self._geturl(path) if path: key = str(rev) + '/' + path else: key = str(rev) dirents_locks = self._dirent_cache.get(key) if not dirents_locks: dirents, locks = list_directory(dir_url, _rev2optrev(rev), _rev2optrev(rev), 0, self.ctx) dirents_locks = [dirents, locks] self._dirent_cache[key] = dirents_locks return dirents_locks[0], dirents_locks[1]
def _get_last_history_rev(self, path_parts, rev): url = self._geturl(self._getpath(path_parts)) optrev = _rev2optrev(rev) revisions = [] def _info_cb(path, info, pool, retval=revisions): revisions.append(info.last_changed_rev) client.svn_client_info(url, optrev, optrev, _info_cb, 0, self.ctx) return revisions[0]
def cat_to_tempfile(svnrepos, path, rev): """Check out file revision to temporary file""" fd, temp = tempfile.mkstemp() fp = os.fdopen(fd, 'wb') url = svnrepos._geturl(path) client.svn_client_cat(fp, url, _rev2optrev(rev), svnrepos.ctx) fp.close() return temp
def cat_to_tempfile(svnrepos, path, rev): """Check out file revision to temporary file""" temp = tempfile.mktemp() stream = core.svn_stream_from_aprfile(temp) url = svnrepos._geturl(path) client.svn_client_cat(core.Stream(stream), url, _rev2optrev(rev), svnrepos.ctx) core.svn_stream_close(stream) return temp
def annotate(self, path_parts, rev, include_text=False): path = self._getpath(path_parts) if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check raise vclib.Error("Path '%s' is not a file." % path) rev = self._getrev(rev) url = self._geturl(path) # Examine logs for the file to determine the oldest revision we are # permitted to see. log_options = { 'svn_cross_copies' : 1, 'svn_show_all_dir_logs' : 1, } revs = self.itemlog(path_parts, rev, vclib.SORTBY_REV, 0, 0, log_options) oldest_rev = revs[-1].number # Now calculate the annotation data. Note that we'll not # inherently trust the provided author and date, because authz # rules might necessitate that we strip that information out. blame_data = [] def _blame_cb(line_no, revision, author, date, line, pool, blame_data=blame_data): prev_rev = None if revision > 1: prev_rev = revision - 1 # If we have an invalid revision, clear the date and author # values. Otherwise, if we have authz filtering to do, use the # revinfo cache to do so. if revision < 0: date = author = None elif self.auth: date, author, msg, revprops, changes = self._revinfo(revision) # Strip text if the caller doesn't want it. if not include_text: line = None blame_data.append(vclib.Annotation(line, line_no + 1, revision, prev_rev, author, date)) client.blame2(url, _rev2optrev(rev), _rev2optrev(oldest_rev), _rev2optrev(rev), _blame_cb, self.ctx) return blame_data, rev
def annotate(self, path_parts, rev): path = self._getpath(path_parts) if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check raise vclib.Error("Path '%s' is not a file." % path) rev = self._getrev(rev) url = self._geturl(path) blame_data = [] def _blame_cb(line_no, revision, author, date, line, pool, blame_data=blame_data): prev_rev = None if revision > 1: prev_rev = revision - 1 blame_data.append(vclib.Annotation(line, line_no+1, revision, prev_rev, author, None)) client.svn_client_blame(url, _rev2optrev(1), _rev2optrev(rev), _blame_cb, self.ctx) return blame_data, rev
def openfile(self, path_parts, rev): path = self._getpath(path_parts) if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check raise vclib.Error("Path '%s' is not a file." % path) rev = self._getrev(rev) url = self._geturl(path) tmp_file = tempfile.mktemp() stream = core.svn_stream_from_aprfile(tmp_file) ### rev here should be the last history revision of the URL client.svn_client_cat(core.Stream(stream), url, _rev2optrev(rev), self.ctx) core.svn_stream_close(stream) return SelfCleanFP(tmp_file), self._get_last_history_rev(path_parts, rev)
def itemlog(self, path_parts, rev, sortby, first, limit, options): assert sortby == vclib.SORTBY_DEFAULT or sortby == vclib.SORTBY_REV path_type = self.itemtype(path_parts, rev) # does auth-check path = self._getpath(path_parts) rev = self._getrev(rev) url = self._geturl(path) # Use ls3 to fetch the lock status for this item. lockinfo = None basename = path_parts and path_parts[-1] or "" dirents, locks = list_directory(url, _rev2optrev(rev), _rev2optrev(rev), 0, self.ctx) if locks.has_key(basename): lockinfo = locks[basename].owner # It's okay if we're told to not show all logs on a file -- all # the revisions should match correctly anyway. lc = LogCollector(path, options.get('svn_show_all_dir_logs', 0), lockinfo) cross_copies = options.get('svn_cross_copies', 0) log_limit = 0 if limit: log_limit = first + limit client.svn_client_log2([url], _rev2optrev(rev), _rev2optrev(1), log_limit, 1, not cross_copies, lc.add_log, self.ctx) revs = lc.logs revs.sort() prev = None for rev in revs: rev.prev = prev prev = rev revs.reverse() if len(revs) < first: return [] if limit: return revs[first:first+limit] return revs
def itemlog(self, path_parts, rev, sortby, first, limit, options): assert sortby == vclib.SORTBY_DEFAULT or sortby == vclib.SORTBY_REV path_type = self.itemtype(path_parts, rev) # does auth-check path = self._getpath(path_parts) rev = self._getrev(rev) url = self._geturl(path) # Use ls3 to fetch the lock status for this item. lockinfo = None basename = path_parts and path_parts[-1] or "" dirents, locks = list_directory(url, _rev2optrev(rev), _rev2optrev(rev), 0, self.ctx) if locks.has_key(basename): lockinfo = locks[basename].owner # It's okay if we're told to not show all logs on a file -- all # the revisions should match correctly anyway. lc = LogCollector(path, options.get('svn_show_all_dir_logs', 0), lockinfo) cross_copies = options.get('svn_cross_copies', 0) log_limit = 0 if limit: log_limit = first + limit client_log(url, _rev2optrev(rev), _rev2optrev(1), log_limit, cross_copies, lc.add_log, self.ctx) revs = lc.logs revs.sort() prev = None for rev in revs: rev.prev = prev prev = rev revs.reverse() if len(revs) < first: return [] if limit: return revs[first:first + limit] return revs
def openfile(self, path_parts, rev, options): path = self._getpath(path_parts) if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check raise vclib.Error("Path '%s' is not a file." % path) rev = self._getrev(rev) url = self._geturl(path) tmp_file = tempfile.mktemp() stream = core.svn_stream_from_aprfile(tmp_file) ### rev here should be the last history revision of the URL client.svn_client_cat(core.Stream(stream), url, _rev2optrev(rev), self.ctx) core.svn_stream_close(stream) return SelfCleanFP(tmp_file), self._get_last_history_rev( path_parts, rev)
def _revinfo_fetch(self, rev, include_changed_paths=0): need_changes = include_changed_paths or self.auth revs = [] def _log_cb(log_entry, pool, retval=revs): # If Subversion happens to call us more than once, we choose not # to care. if retval: return revision = log_entry.revision msg, author, date, revprops = _split_revprops(log_entry.revprops) action_map = { 'D': vclib.DELETED, 'A': vclib.ADDED, 'R': vclib.REPLACED, 'M': vclib.MODIFIED, } # Easy out: if we won't use the changed-path info, just return a # changes-less tuple. if not need_changes: return revs.append([date, author, msg, revprops, None]) # Subversion 1.5 and earlier didn't offer the 'changed_paths2' # hash, and in Subversion 1.6, it's offered but broken. try: changed_paths = log_entry.changed_paths2 paths = (changed_paths or {}).keys() except: changed_paths = log_entry.changed_paths paths = (changed_paths or {}).keys() paths.sort(lambda a, b: _compare_paths(a, b)) # If we get this far, our caller needs changed-paths, or we need # them for authz-related sanitization. changes = [] found_readable = found_unreadable = 0 for path in paths: change = changed_paths[path] # svn_log_changed_path_t (which we might get instead of the # svn_log_changed_path2_t we'd prefer) doesn't have the # 'node_kind' member. pathtype = None if hasattr(change, 'node_kind'): if change.node_kind == core.svn_node_dir: pathtype = vclib.DIR elif change.node_kind == core.svn_node_file: pathtype = vclib.FILE # svn_log_changed_path2_t only has the 'text_modified' and # 'props_modified' bits in Subversion 1.7 and beyond. And # svn_log_changed_path_t is without. text_modified = props_modified = 0 if hasattr(change, 'text_modified'): if change.text_modified == core.svn_tristate_true: text_modified = 1 if hasattr(change, 'props_modified'): if change.props_modified == core.svn_tristate_true: props_modified = 1 # Wrong, diddily wrong wrong wrong. Can you say, # "Manufacturing data left and right because it hurts to # figure out the right stuff?" action = action_map.get(change.action, vclib.MODIFIED) if change.copyfrom_path and change.copyfrom_rev: is_copy = 1 base_path = change.copyfrom_path base_rev = change.copyfrom_rev elif action == vclib.ADDED or action == vclib.REPLACED: is_copy = 0 base_path = base_rev = None else: is_copy = 0 base_path = path base_rev = revision - 1 # Check authz rules (sadly, we have to lie about the path type) parts = _path_parts(path) if vclib.check_path_access(self, parts, vclib.FILE, revision): if is_copy and base_path and (base_path != path): parts = _path_parts(base_path) if not vclib.check_path_access(self, parts, vclib.FILE, base_rev): is_copy = 0 base_path = None base_rev = None found_unreadable = 1 changes.append( SVNChangedPath(path, revision, pathtype, base_path, base_rev, action, is_copy, text_modified, props_modified)) found_readable = 1 else: found_unreadable = 1 # If our caller doesn't want changed-path stuff, and we have # the info we need to make an authz determination already, # quit this loop and get on with it. if (not include_changed_paths ) and found_unreadable and found_readable: break # Filter unreadable information. if found_unreadable: msg = None if not found_readable: author = None date = None # Drop unrequested changes. if not include_changed_paths: changes = None # Add this revision information to the "return" array. retval.append([date, author, msg, revprops, changes]) optrev = _rev2optrev(rev) client_log(self.rootpath, optrev, optrev, 1, need_changes, 0, _log_cb, self.ctx) return tuple(revs[0])
def _revinfo_raw(self, rev): # return 5-tuple (date, author, msg, revprops, changes) optrev = _rev2optrev(rev) revs = [] def _log_cb(log_entry, pool, retval=revs): ### Subversion 1.5 and earlier didn't offer the 'changed_paths2' ### hash, and in Subversion 1.6, it's offered but broken. try: changed_paths = log_entry.changed_paths2 paths = (changed_paths or {}).keys() except: changed_paths = log_entry.changed_paths paths = (changed_paths or {}).keys() paths.sort(lambda a, b: _compare_paths(a, b)) revision = log_entry.revision msg, author, date, revprops = _split_revprops(log_entry.revprops) action_map = { 'D': vclib.DELETED, 'A': vclib.ADDED, 'R': vclib.REPLACED, 'M': vclib.MODIFIED, } changes = [] found_readable = found_unreadable = 0 for path in paths: change = changed_paths[path] ### svn_log_changed_path_t (which we might get instead of the ### svn_log_changed_path2_t we'd prefer) doesn't have the ### 'node_kind' member. pathtype = None if hasattr(change, 'node_kind'): if change.node_kind == core.svn_node_dir: pathtype = vclib.DIR elif change.node_kind == core.svn_node_file: pathtype = vclib.FILE ### svn_log_changed_path2_t only has the 'text_modified' and ### 'props_modified' bits in Subversion 1.7 and beyond. And ### svn_log_changed_path_t is without. text_modified = props_modified = 0 if hasattr(change, 'text_modified'): if change.text_modified == core.svn_tristate_true: text_modified = 1 if hasattr(change, 'props_modified'): if change.props_modified == core.svn_tristate_true: props_modified = 1 ### Wrong, diddily wrong wrong wrong. Can you say, ### "Manufacturing data left and right because it hurts to ### figure out the right stuff?" action = action_map.get(change.action, vclib.MODIFIED) if change.copyfrom_path and change.copyfrom_rev: is_copy = 1 base_path = change.copyfrom_path base_rev = change.copyfrom_rev elif action == vclib.ADDED or action == vclib.REPLACED: is_copy = 0 base_path = base_rev = None else: is_copy = 0 base_path = path base_rev = revision - 1 ### Check authz rules (we lie about the path type) parts = _path_parts(path) if vclib.check_path_access(self, parts, vclib.FILE, revision): if is_copy and base_path and (base_path != path): parts = _path_parts(base_path) if vclib.check_path_access(self, parts, vclib.FILE, base_rev): is_copy = 0 base_path = None base_rev = None changes.append( SVNChangedPath(path, revision, pathtype, base_path, base_rev, action, is_copy, text_modified, props_modified)) found_readable = 1 else: found_unreadable = 1 if found_unreadable: msg = None if not found_readable: author = None date = None revs.append([date, author, msg, revprops, changes]) client_log(self.rootpath, optrev, optrev, 1, 0, _log_cb, self.ctx) return tuple(revs[0])
def itemlog(self, path_parts, rev, sortby, first, limit, options): assert sortby == vclib.SORTBY_DEFAULT or sortby == vclib.SORTBY_REV path_type = self.itemtype(path_parts, rev) # does auth-check path = self._getpath(path_parts) rev = self._getrev(rev) url = self._geturl(path) # If this is a file, fetch the lock status and size (as of REV) # for this item. lockinfo = size_in_rev = None if path_type == vclib.FILE: basename = path_parts[-1] list_url = self._geturl(self._getpath(path_parts[:-1])) dirents, locks = list_directory(list_url, _rev2optrev(rev), _rev2optrev(rev), 0, self.ctx) if locks.has_key(basename): lockinfo = locks[basename].owner if dirents.has_key(basename): size_in_rev = dirents[basename].size # Special handling for the 'svn_latest_log' scenario. ### FIXME: Don't like this hack. We should just introduce ### something more direct in the vclib API. if options.get('svn_latest_log', 0): dir_lh_rev, dir_c_rev = self._get_last_history_rev(path_parts, rev) date, author, log, revprops, changes = self._revinfo(dir_lh_rev) return [ vclib.Revision(dir_lh_rev, str(dir_lh_rev), date, author, None, log, size_in_rev, lockinfo) ] def _access_checker(check_path, check_rev): return vclib.check_path_access(self, _path_parts(check_path), path_type, check_rev) # It's okay if we're told to not show all logs on a file -- all # the revisions should match correctly anyway. lc = LogCollector(path, options.get('svn_show_all_dir_logs', 0), lockinfo, _access_checker) cross_copies = options.get('svn_cross_copies', 0) log_limit = 0 if limit: log_limit = first + limit client_log(url, _rev2optrev(rev), _rev2optrev(1), log_limit, 1, cross_copies, lc.add_log, self.ctx) revs = lc.logs revs.sort() prev = None for rev in revs: # Swap out revision info with stuff from the cache (which is # authz-sanitized). rev.date, rev.author, rev.log, revprops, changes \ = self._revinfo(rev.number) rev.prev = prev prev = rev revs.reverse() if len(revs) < first: return [] if limit: return revs[first:first + limit] return revs
def _revinfo_fetch(self, rev, include_changed_paths=0): need_changes = include_changed_paths or self.auth revs = [] def _log_cb(log_entry, pool, retval=revs): # If Subversion happens to call us more than once, we choose not # to care. if retval: return revision = log_entry.revision msg, author, date, revprops = _split_revprops(log_entry.revprops) action_map = { 'D' : vclib.DELETED, 'A' : vclib.ADDED, 'R' : vclib.REPLACED, 'M' : vclib.MODIFIED, } # Easy out: if we won't use the changed-path info, just return a # changes-less tuple. if not need_changes: return revs.append([date, author, msg, revprops, None]) # Subversion 1.5 and earlier didn't offer the 'changed_paths2' # hash, and in Subversion 1.6, it's offered but broken. try: changed_paths = log_entry.changed_paths2 paths = (changed_paths or {}).keys() except: changed_paths = log_entry.changed_paths paths = (changed_paths or {}).keys() paths.sort(lambda a, b: _compare_paths(a, b)) # If we get this far, our caller needs changed-paths, or we need # them for authz-related sanitization. changes = [] found_readable = found_unreadable = 0 for path in paths: change = changed_paths[path] # svn_log_changed_path_t (which we might get instead of the # svn_log_changed_path2_t we'd prefer) doesn't have the # 'node_kind' member. pathtype = None if hasattr(change, 'node_kind'): if change.node_kind == core.svn_node_dir: pathtype = vclib.DIR elif change.node_kind == core.svn_node_file: pathtype = vclib.FILE # svn_log_changed_path2_t only has the 'text_modified' and # 'props_modified' bits in Subversion 1.7 and beyond. And # svn_log_changed_path_t is without. text_modified = props_modified = 0 if hasattr(change, 'text_modified'): if change.text_modified == core.svn_tristate_true: text_modified = 1 if hasattr(change, 'props_modified'): if change.props_modified == core.svn_tristate_true: props_modified = 1 # Wrong, diddily wrong wrong wrong. Can you say, # "Manufacturing data left and right because it hurts to # figure out the right stuff?" action = action_map.get(change.action, vclib.MODIFIED) if change.copyfrom_path and change.copyfrom_rev: is_copy = 1 base_path = change.copyfrom_path base_rev = change.copyfrom_rev elif action == vclib.ADDED or action == vclib.REPLACED: is_copy = 0 base_path = base_rev = None else: is_copy = 0 base_path = path base_rev = revision - 1 # Check authz rules (sadly, we have to lie about the path type) parts = _path_parts(path) if vclib.check_path_access(self, parts, vclib.FILE, revision): if is_copy and base_path and (base_path != path): parts = _path_parts(base_path) if not vclib.check_path_access(self, parts, vclib.FILE, base_rev): is_copy = 0 base_path = None base_rev = None found_unreadable = 1 changes.append(SVNChangedPath(path, revision, pathtype, base_path, base_rev, action, is_copy, text_modified, props_modified)) found_readable = 1 else: found_unreadable = 1 # If our caller doesn't want changed-path stuff, and we have # the info we need to make an authz determination already, # quit this loop and get on with it. if (not include_changed_paths) and found_unreadable and found_readable: break # Filter unreadable information. if found_unreadable: msg = None if not found_readable: author = None date = None # Drop unrequested changes. if not include_changed_paths: changes = None # Add this revision information to the "return" array. retval.append([date, author, msg, revprops, changes]) optrev = _rev2optrev(rev) client_log(self.rootpath, optrev, optrev, 1, need_changes, 0, _log_cb, self.ctx) return tuple(revs[0])
def _revinfo_raw(self, rev): # return 5-tuple (date, author, message, changes) optrev = _rev2optrev(rev) revs = [] def _log_cb(changed_paths, revision, author, datestr, message, pool, retval=revs): date = _datestr_to_date(datestr) action_map = { 'D' : vclib.DELETED, 'A' : vclib.ADDED, 'R' : vclib.REPLACED, 'M' : vclib.MODIFIED, } paths = (changed_paths or {}).keys() paths.sort(lambda a, b: _compare_paths(a, b)) changes = [] found_readable = found_unreadable = 0 for path in paths: pathtype = None change = changed_paths[path] action = action_map.get(change.action, vclib.MODIFIED) ### Wrong, diddily wrong wrong wrong. Can you say, ### "Manufacturing data left and right because it hurts to ### figure out the right stuff?" if change.copyfrom_path and change.copyfrom_rev: is_copy = 1 base_path = change.copyfrom_path base_rev = change.copyfrom_rev elif action == vclib.ADDED or action == vclib.REPLACED: is_copy = 0 base_path = base_rev = None else: is_copy = 0 base_path = path base_rev = revision - 1 ### Check authz rules (we lie about the path type) parts = _path_parts(path) if vclib.check_path_access(self, parts, vclib.FILE, revision): if is_copy and base_path and (base_path != path): parts = _path_parts(base_path) if vclib.check_path_access(self, parts, vclib.FILE, base_rev): is_copy = 0 base_path = None base_rev = None changes.append(SVNChangedPath(path, revision, pathtype, base_path, base_rev, action, is_copy, 0, 0)) found_readable = 1 else: found_unreadable = 1 if found_unreadable: message = None if not found_readable: author = None date = None revs.append([date, author, message, changes]) client.svn_client_log([self.rootpath], optrev, optrev, 1, 0, _log_cb, self.ctx) return revs[0][0], revs[0][1], revs[0][2], revs[0][3]
def _revinfo_raw(self, rev): # return 5-tuple (date, author, msg, revprops, changes) optrev = _rev2optrev(rev) revs = [] def _log_cb(log_entry, pool, retval=revs): ### Subversion 1.5 and earlier didn't offer the 'changed_paths2' ### hash, and in Subversion 1.6, it's offered but broken. try: changed_paths = log_entry.changed_paths2 paths = (changed_paths or {}).keys() except: changed_paths = log_entry.changed_paths paths = (changed_paths or {}).keys() paths.sort(lambda a, b: _compare_paths(a, b)) revision = log_entry.revision msg, author, date, revprops = _split_revprops(log_entry.revprops) action_map = { 'D' : vclib.DELETED, 'A' : vclib.ADDED, 'R' : vclib.REPLACED, 'M' : vclib.MODIFIED, } changes = [] found_readable = found_unreadable = 0 for path in paths: change = changed_paths[path] ### svn_log_changed_path_t (which we might get instead of the ### svn_log_changed_path2_t we'd prefer) doesn't have the ### 'node_kind' member. pathtype = None if hasattr(change, 'node_kind'): if change.node_kind == core.svn_node_dir: pathtype = vclib.DIR elif change.node_kind == core.svn_node_file: pathtype = vclib.FILE ### svn_log_changed_path2_t only has the 'text_modified' and ### 'props_modified' bits in Subversion 1.7 and beyond. And ### svn_log_changed_path_t is without. text_modified = props_modified = 0 if hasattr(change, 'text_modified'): if change.text_modified == core.svn_tristate_true: text_modified = 1 if hasattr(change, 'props_modified'): if change.props_modified == core.svn_tristate_true: props_modified = 1 ### Wrong, diddily wrong wrong wrong. Can you say, ### "Manufacturing data left and right because it hurts to ### figure out the right stuff?" action = action_map.get(change.action, vclib.MODIFIED) if change.copyfrom_path and change.copyfrom_rev: is_copy = 1 base_path = change.copyfrom_path base_rev = change.copyfrom_rev elif action == vclib.ADDED or action == vclib.REPLACED: is_copy = 0 base_path = base_rev = None else: is_copy = 0 base_path = path base_rev = revision - 1 ### Check authz rules (we lie about the path type) parts = _path_parts(path) if vclib.check_path_access(self, parts, vclib.FILE, revision): if is_copy and base_path and (base_path != path): parts = _path_parts(base_path) if vclib.check_path_access(self, parts, vclib.FILE, base_rev): is_copy = 0 base_path = None base_rev = None changes.append(SVNChangedPath(path, revision, pathtype, base_path, base_rev, action, is_copy, text_modified, props_modified)) found_readable = 1 else: found_unreadable = 1 if found_unreadable: msg = None if not found_readable: author = None date = None revs.append([date, author, msg, revprops, changes]) client_log(self.rootpath, optrev, optrev, 1, 0, _log_cb, self.ctx) return tuple(revs[0])