From patchwork Wed Mar 5 19:05:08 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [2,of,2] merge: adds documentation to the mergestate class From: Pierre-Yves David X-Patchwork-Id: 3865 Message-Id: <7760e02d58f2f00dd944.1394046308@marginatus.alto.octopoid.net> To: mercurial-devel@selenic.com Cc: pierre-yves.david@ens-lyon.org Date: Wed, 05 Mar 2014 11:05:08 -0800 # HG changeset patch # User Pierre-Yves David # Date 1394045383 28800 # Wed Mar 05 10:49:43 2014 -0800 # Node ID 7760e02d58f2f00dd944ce585af63b8e05cfc69f # Parent 37d4c6705c2470d788ad9ed4af3d1d6f27400032 merge: adds documentation to the mergestate class Document most the new function involved in the new serialisation process (and a few others). diff --git a/mercurial/merge.py b/mercurial/merge.py --- a/mercurial/merge.py +++ b/mercurial/merge.py @@ -60,10 +60,15 @@ class mergestate(object): self._other = other shutil.rmtree(self._repo.join("merge"), True) self._dirty = False def _read(self): + """Analyse each record content to restore a serialized state from disk + + This function process "record" entry produced by the de-serialization + of on disk file. + """ self._state = {} records = self._readrecords() for rtype, record in records: if rtype == 'L': self._local = bin(record) @@ -76,10 +81,23 @@ class mergestate(object): raise util.Abort(_('unsupported merge state record:' % rtype)) self._dirty = False def _readrecords(self): + """Read merge state from disk and return a list of record (TYPE, data) + + We read data from both V1 and Ve files decide which on to use. + + V1 have been used by version prior to 2.9.1 and contains less data than + v2. We read both version and check if no data in v2 contradict one in + v1. If there is not contradiction we can safely assume that both v1 + and v2 were written at the same time and use the extract data in v2. If + there is contradiction we ignore v2 content as we assume an old version + of Mercurial have over written the mergstate file and left an old v2 + file around. + + returns list of record [(TYPE, data), …]""" v1records = self._readrecordsv1() v2records = self._readrecordsv2() oldv2 = set() # old format version of v2 record for rec in v2records: if rec[0] == 'L': @@ -105,10 +123,17 @@ class mergestate(object): return v1records else: return v2records def _readrecordsv1(self): + """read on disk merge state for version 1 file + + returns list of record [(TYPE, data), …] + + Note: the "F" data from this file are one entry short + (no "other file node" entry) + """ records = [] try: f = self._repo.opener(self.statepathv1) for i, l in enumerate(f): if i == 0: @@ -120,10 +145,14 @@ class mergestate(object): if err.errno != errno.ENOENT: raise return records def _readrecordsv2(self): + """read on disk merge state for version 2 file + + returns list of record [(TYPE, data), …] + """ records = [] try: f = self._repo.opener(self.statepathv2) data = f.read() off = 0 @@ -141,24 +170,27 @@ class mergestate(object): if err.errno != errno.ENOENT: raise return records def commit(self): + """Write current state on disk (if necessary)""" if self._dirty: records = [] records.append(("L", hex(self._local))) records.append(("O", hex(self._other))) for d, v in self._state.iteritems(): records.append(("F", "\0".join([d] + v))) self._writerecords(records) self._dirty = False def _writerecords(self, records): + """Write current state on disk (both v1 and v2)""" self._writerecordsv1(records) self._writerecordsv2(records) def _writerecordsv1(self, records): + """Write current state on disk in a version 1 file""" f = self._repo.opener(self.statepathv1, "w") irecords = iter(records) lrecords = irecords.next() assert lrecords[0] == 'L' f.write(hex(self._local) + "\n") @@ -166,18 +198,27 @@ class mergestate(object): if rtype == "F": f.write("%s\n" % _droponode(data)) f.close() def _writerecordsv2(self, records): + """Write current state on disk in a version 2 file""" f = self._repo.opener(self.statepathv2, "w") for key, data in records: assert len(key) == 1 format = ">sI%is" % len(data) f.write(_pack(format, key, len(data), data)) f.close() def add(self, fcl, fco, fca, fd): + """add a new (potentially?) conflicting file the merge state + fcl: file context for local, + fco: file context for remote, + fca: file context for ancestors, + fd: file path of the resulting merge. + + note: also write the local version to the `.hg/merge` directory. + """ hash = util.sha1(fcl.path()).hexdigest() self._repo.opener.write("merge/" + hash, fcl.data()) self._state[fd] = ['u', hash, fcl.path(), fca.path(), hex(fca.filenode()), fco.path(), hex(fco.filenode()), @@ -202,10 +243,11 @@ class mergestate(object): def mark(self, dfile, state): self._state[dfile][0] = state self._dirty = True def resolve(self, dfile, wctx): + """rerun merge process for file path `dfile`""" if self[dfile] == 'r': return 0 stateentry = self._state[dfile] state, hash, lfile, afile, anode, ofile, onode, flags = stateentry octx = self._repo[self._other]