diff --git a/mercurial/repair.py b/mercurial/repair.py --- a/mercurial/repair.py +++ b/mercurial/repair.py @@ -392,9 +392,7 @@ def rebuildfncache(ui, repo): with repo.lock(): fnc = repo.store.fncache - # Trigger load of fncache. - if 'irrelevant' in fnc: - pass + fnc.ensureloaded(warn=ui.warn) oldentries = set(fnc.entries) newentries = set() diff --git a/mercurial/store.py b/mercurial/store.py --- a/mercurial/store.py +++ b/mercurial/store.py @@ -458,7 +458,15 @@ class fncache(object): # set of new additions to fncache self.addls = set() - def _load(self): + def ensureloaded(self, warn=None): + '''read the fncache file if not already read. + + If the file on disk is corrupted, raise. If warn is provided, + warn and keep going instead.''' + if self.entries is None: + self._load(warn) + + def _load(self, warn=None): '''fill the entries from the fncache file''' self._dirty = False try: @@ -482,20 +490,27 @@ class fncache(object): pass if chunk: - raise error.Abort(_("fncache does not ends with a newline"), - hint=_("use 'hg debugrebuildfncache' to rebuild" - " the fncache")) - self._checkentries(fp) + msg = _("fncache does not ends with a newline") + if warn: + warn(msg + '\n') + else: + raise error.Abort(msg, + hint=_("use 'hg debugrebuildfncache' to " + "rebuild the fncache")) + self._checkentries(fp, warn) fp.close() - def _checkentries(self, fp): + def _checkentries(self, fp, warn): """ make sure there is no empty string in entries """ if '' in self.entries: fp.seek(0) for n, line in enumerate(util.iterfile(fp)): if not line.rstrip('\n'): t = _('invalid entry in fncache, line %d') % (n + 1) - raise error.Abort(t) + if warn: + warn(t + '\n') + else: + raise error.Abort(t) def write(self, tr): if self._dirty: diff --git a/tests/test-fncache.t b/tests/test-fncache.t --- a/tests/test-fncache.t +++ b/tests/test-fncache.t @@ -435,6 +435,19 @@ A single missing file should get restore data/.bar.i data/foo.i +debugrebuildfncache recovers from truncated line in fncache + + $ printf a > .hg/store/fncache + $ hg debugrebuildfncache + fncache does not ends with a newline + adding data/.bar.i + adding data/foo.i + 2 items added, 0 removed from fncache + + $ cat .hg/store/fncache | sort + data/.bar.i + data/foo.i + $ cd .. Try a simple variation without dotencode to ensure fncache is ignorant of encoding diff --git a/tests/test-run-tests.t b/tests/test-run-tests.t --- a/tests/test-run-tests.t +++ b/tests/test-run-tests.t @@ -1030,7 +1030,7 @@ test for --time # Ran 1 tests, 0 skipped, 0 failed. # Producing time report start end cuser csys real Test - \s*[\d\.]{5,8} \s*[\d\.]{5,8} \s*[\d\.]{5,8} \s*[\d\.]{5,8} \s*[\d\.]{5,8} test-success.t (re) + \s*[\d\.]{5,8} \s*[\d\.]{5,8} \s*[\d\.]{5,8} \s*[\d\.]{5,8} \s*[\d\.]{5,8} test-success.t (re) test for --time with --job enabled ==================================== @@ -1041,7 +1041,7 @@ test for --time with --job enabled # Ran 1 tests, 0 skipped, 0 failed. # Producing time report start end cuser csys real Test - \s*[\d\.]{5,8} \s*[\d\.]{5,8} \s*[\d\.]{5,8} \s*[\d\.]{5,8} \s*[\d\.]{5,8} test-success.t (re) + \s*[\d\.]{5,8} \s*[\d\.]{5,8} \s*[\d\.]{5,8} \s*[\d\.]{5,8} \s*[\d\.]{5,8} test-success.t (re) Skips ================