mercurial/merge.py
changeset 20652 2a4871c2511d
parent 20651 c1a52dd56eb4
child 20792 89059c450c56
equal deleted inserted replaced
20651:c1a52dd56eb4 20652:2a4871c2511d
    60             self._other = other
    60             self._other = other
    61         shutil.rmtree(self._repo.join("merge"), True)
    61         shutil.rmtree(self._repo.join("merge"), True)
    62         self._dirty = False
    62         self._dirty = False
    63 
    63 
    64     def _read(self):
    64     def _read(self):
       
    65         """Analyse each record content to restore a serialized state from disk
       
    66 
       
    67         This function process "record" entry produced by the de-serialization
       
    68         of on disk file.
       
    69         """
    65         self._state = {}
    70         self._state = {}
    66         records = self._readrecords()
    71         records = self._readrecords()
    67         for rtype, record in records:
    72         for rtype, record in records:
    68             if rtype == 'L':
    73             if rtype == 'L':
    69                 self._local = bin(record)
    74                 self._local = bin(record)
    76                 raise util.Abort(_('unsupported merge state record:'
    81                 raise util.Abort(_('unsupported merge state record:'
    77                                    % rtype))
    82                                    % rtype))
    78         self._dirty = False
    83         self._dirty = False
    79 
    84 
    80     def _readrecords(self):
    85     def _readrecords(self):
       
    86         """Read merge state from disk and return a list of record (TYPE, data)
       
    87 
       
    88         We read data from both V1 and Ve files decide which on to use.
       
    89 
       
    90         V1 have been used by version prior to 2.9.1 and contains less data than
       
    91         v2. We read both version and check if no data in v2 contradict one in
       
    92         v1. If there is not contradiction we can safely assume that both v1
       
    93         and v2 were written at the same time and use the extract data in v2. If
       
    94         there is contradiction we ignore v2 content as we assume an old version
       
    95         of Mercurial have over written the mergstate file and left an old v2
       
    96         file around.
       
    97 
       
    98         returns list of record [(TYPE, data), ...]"""
    81         v1records = self._readrecordsv1()
    99         v1records = self._readrecordsv1()
    82         v2records = self._readrecordsv2()
   100         v2records = self._readrecordsv2()
    83         oldv2 = set() # old format version of v2 record
   101         oldv2 = set() # old format version of v2 record
    84         for rec in v2records:
   102         for rec in v2records:
    85             if rec[0] == 'L':
   103             if rec[0] == 'L':
   105                 return v1records
   123                 return v1records
   106         else:
   124         else:
   107             return v2records
   125             return v2records
   108 
   126 
   109     def _readrecordsv1(self):
   127     def _readrecordsv1(self):
       
   128         """read on disk merge state for version 1 file
       
   129 
       
   130         returns list of record [(TYPE, data), ...]
       
   131 
       
   132         Note: the "F" data from this file are one entry short
       
   133               (no "other file node" entry)
       
   134         """
   110         records = []
   135         records = []
   111         try:
   136         try:
   112             f = self._repo.opener(self.statepathv1)
   137             f = self._repo.opener(self.statepathv1)
   113             for i, l in enumerate(f):
   138             for i, l in enumerate(f):
   114                 if i == 0:
   139                 if i == 0:
   120             if err.errno != errno.ENOENT:
   145             if err.errno != errno.ENOENT:
   121                 raise
   146                 raise
   122         return records
   147         return records
   123 
   148 
   124     def _readrecordsv2(self):
   149     def _readrecordsv2(self):
       
   150         """read on disk merge state for version 2 file
       
   151 
       
   152         returns list of record [(TYPE, data), ...]
       
   153         """
   125         records = []
   154         records = []
   126         try:
   155         try:
   127             f = self._repo.opener(self.statepathv2)
   156             f = self._repo.opener(self.statepathv2)
   128             data = f.read()
   157             data = f.read()
   129             off = 0
   158             off = 0
   141             if err.errno != errno.ENOENT:
   170             if err.errno != errno.ENOENT:
   142                 raise
   171                 raise
   143         return records
   172         return records
   144 
   173 
   145     def commit(self):
   174     def commit(self):
       
   175         """Write current state on disk (if necessary)"""
   146         if self._dirty:
   176         if self._dirty:
   147             records = []
   177             records = []
   148             records.append(("L", hex(self._local)))
   178             records.append(("L", hex(self._local)))
   149             records.append(("O", hex(self._other)))
   179             records.append(("O", hex(self._other)))
   150             for d, v in self._state.iteritems():
   180             for d, v in self._state.iteritems():
   151                 records.append(("F", "\0".join([d] + v)))
   181                 records.append(("F", "\0".join([d] + v)))
   152             self._writerecords(records)
   182             self._writerecords(records)
   153             self._dirty = False
   183             self._dirty = False
   154 
   184 
   155     def _writerecords(self, records):
   185     def _writerecords(self, records):
       
   186         """Write current state on disk (both v1 and v2)"""
   156         self._writerecordsv1(records)
   187         self._writerecordsv1(records)
   157         self._writerecordsv2(records)
   188         self._writerecordsv2(records)
   158 
   189 
   159     def _writerecordsv1(self, records):
   190     def _writerecordsv1(self, records):
       
   191         """Write current state on disk in a version 1 file"""
   160         f = self._repo.opener(self.statepathv1, "w")
   192         f = self._repo.opener(self.statepathv1, "w")
   161         irecords = iter(records)
   193         irecords = iter(records)
   162         lrecords = irecords.next()
   194         lrecords = irecords.next()
   163         assert lrecords[0] == 'L'
   195         assert lrecords[0] == 'L'
   164         f.write(hex(self._local) + "\n")
   196         f.write(hex(self._local) + "\n")
   166             if rtype == "F":
   198             if rtype == "F":
   167                 f.write("%s\n" % _droponode(data))
   199                 f.write("%s\n" % _droponode(data))
   168         f.close()
   200         f.close()
   169 
   201 
   170     def _writerecordsv2(self, records):
   202     def _writerecordsv2(self, records):
       
   203         """Write current state on disk in a version 2 file"""
   171         f = self._repo.opener(self.statepathv2, "w")
   204         f = self._repo.opener(self.statepathv2, "w")
   172         for key, data in records:
   205         for key, data in records:
   173             assert len(key) == 1
   206             assert len(key) == 1
   174             format = ">sI%is" % len(data)
   207             format = ">sI%is" % len(data)
   175             f.write(_pack(format, key, len(data), data))
   208             f.write(_pack(format, key, len(data), data))
   176         f.close()
   209         f.close()
   177 
   210 
   178     def add(self, fcl, fco, fca, fd):
   211     def add(self, fcl, fco, fca, fd):
       
   212         """add a new (potentially?) conflicting file the merge state
       
   213         fcl: file context for local,
       
   214         fco: file context for remote,
       
   215         fca: file context for ancestors,
       
   216         fd:  file path of the resulting merge.
       
   217 
       
   218         note: also write the local version to the `.hg/merge` directory.
       
   219         """
   179         hash = util.sha1(fcl.path()).hexdigest()
   220         hash = util.sha1(fcl.path()).hexdigest()
   180         self._repo.opener.write("merge/" + hash, fcl.data())
   221         self._repo.opener.write("merge/" + hash, fcl.data())
   181         self._state[fd] = ['u', hash, fcl.path(),
   222         self._state[fd] = ['u', hash, fcl.path(),
   182                            fca.path(), hex(fca.filenode()),
   223                            fca.path(), hex(fca.filenode()),
   183                            fco.path(), hex(fco.filenode()),
   224                            fco.path(), hex(fco.filenode()),
   202     def mark(self, dfile, state):
   243     def mark(self, dfile, state):
   203         self._state[dfile][0] = state
   244         self._state[dfile][0] = state
   204         self._dirty = True
   245         self._dirty = True
   205 
   246 
   206     def resolve(self, dfile, wctx):
   247     def resolve(self, dfile, wctx):
       
   248         """rerun merge process for file path `dfile`"""
   207         if self[dfile] == 'r':
   249         if self[dfile] == 'r':
   208             return 0
   250             return 0
   209         stateentry = self._state[dfile]
   251         stateentry = self._state[dfile]
   210         state, hash, lfile, afile, anode, ofile, onode, flags = stateentry
   252         state, hash, lfile, afile, anode, ofile, onode, flags = stateentry
   211         octx = self._repo[self._other]
   253         octx = self._repo[self._other]