def check_file(self, path, content): """Check if there is a file at path with content. :raises: ValueError if there a non-file at path. :return: True if there is a file present with the right content. """ try: st = self.contentdir.stat(path) if osutils.file_kind_from_stat_mode(st.st_mode) != 'file': raise ValueError('unexpected non-file at %r' % path) f = self.contentdir.get(path) try: self.ui.output_log(4, __name__, 'Hashing %s %r' % (content.kind, path)) size, sha1 = osutils.size_sha_file(f) finally: f.close() return sha1 == content.sha1 and size == content.length except errors.NoSuchFile: return False
def _finished_scan(self, dir_contents, missing_is_unchanged=False): """Perform finished() by scanning the disk. :param dir_contents: A callback to get the contents of a directory. :param missing_is_unchanged: If True, a path not listed in a directory is unchanged, rather than missing. """ pending = [''] while pending: dirname = pending.pop(-1) names = dir_contents(dirname) # NB: quadratic in lookup here due to presence in inner loop: # consider tuning. segments = dirname.split('/') cwd = self.tree for segment in segments: if not segment: continue try: cwd = cwd[segment] except KeyError: # totally new directory - added to journal by the directory # above. cwd = {} # tree_names contains the last recorded set of names. tree_names = set(cwd) names = set(names) if not missing_is_unchanged: for name in tree_names - names: # deletes path = dirname and ('%s/%s' % (dirname, name)) or name old_kind_details = cwd[name] if type(old_kind_details) is dict: self._gather_deleted_dir(path, old_kind_details) old_kind_details = DirContent() self.journal.add(path, 'del', old_kind_details) new_names = names - tree_names for name in names: path = dirname and ('%s/%s' % (dirname, name)) or name if self._skip_path(path): if name in tree_names: # Newly excluded. old_kind_details = cwd[name] if type(old_kind_details) is dict: self._gather_deleted_dir(path, old_kind_details) old_kind_details = DirContent() self.journal.add(path, 'del', old_kind_details) continue try: statinfo = self.transport.stat(path) except errors.NoSuchFile: # This file doesn't actually exist: may be concurrent # delete, or a seen change from a changes list. if name in tree_names: # A delete. old_kind_details = cwd[name] if type(old_kind_details) is dict: self._gather_deleted_dir(path, old_kind_details) old_kind_details = DirContent() self.journal.add(path, 'del', old_kind_details) continue mtime = getattr(statinfo, 'st_mtime', 0) kind = osutils.file_kind_from_stat_mode(statinfo.st_mode) if (kind != 'directory' and (self.last_timestamp - mtime > 3 and mtime) and name not in new_names): # We have to look inside directories always; things that # are older than 3 seconds we can trust even FAT to not # be lying about the last-modification (it has 2 second # granularity) and finally its not new (new things have # to be scanned always). continue if kind == 'file': f = self.transport.get(path) try: disk_size, disk_sha1 = osutils.size_sha_file(f) finally: f.close() new_kind_details = FileContent(disk_sha1, disk_size, statinfo.st_mtime) elif kind == 'symlink': new_kind_details = SymlinkContent(os.readlink(self.transport.local_abspath(path))) elif kind == 'directory': new_kind_details = DirContent() pending.append(path) else: raise ValueError('unknown kind %r for %r' % (kind, path)) if name in new_names: self.journal.add(path, 'new', new_kind_details) else: old_kind_details = cwd[name] if type(old_kind_details) is dict: old_kind_details = DirContent() if old_kind_details != new_kind_details: self.journal.add(path, 'replace', (old_kind_details, new_kind_details)) for path, (action, details) in self.journal.paths.iteritems(): self.ui.output_log(4, __name__, 'Journalling action %s for %r' % ( action, path)) return self.journal