bzr branch
http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
| 974.1.27
by aaron.bentley at utoronto Initial greedy fetch work | 1 | # Copyright (C) 2005 by Canonical Ltd
 | 
| 2 | ||
| 3 | # This program is free software; you can redistribute it and/or modify
 | |
| 4 | # it under the terms of the GNU General Public License as published by
 | |
| 5 | # the Free Software Foundation; either version 2 of the License, or
 | |
| 6 | # (at your option) any later version.
 | |
| 7 | ||
| 8 | # This program is distributed in the hope that it will be useful,
 | |
| 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| 11 | # GNU General Public License for more details.
 | |
| 12 | ||
| 13 | # You should have received a copy of the GNU General Public License
 | |
| 14 | # along with this program; if not, write to the Free Software
 | |
| 15 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | |
| 1218
by Martin Pool - fix up import | 16 | |
| 1480
by Robert Collins BUGFIX: fetch was not skipping all missing parents for inventory insertion | 17 | from copy import copy | 
| 1218
by Martin Pool - fix up import | 18 | import os | 
| 1231
by Martin Pool - more progress on fetch on top of weaves | 19 | from cStringIO import StringIO | 
| 1218
by Martin Pool - fix up import | 20 | |
| 1185.13.4
by Robert Collins make reweave visible as a weave method, and quickly integrate into fetch | 21 | import bzrlib | 
| 22 | import bzrlib.errors as errors | |
| 1185.35.42
by Aaron Bentley Fixed fetch to be safer wrt ghosts and corrupt branches | 23 | from bzrlib.errors import (InstallFailed, NoSuchRevision, WeaveError, | 
| 24 | MissingText) | |
| 1231
by Martin Pool - more progress on fetch on top of weaves | 25 | from bzrlib.trace import mutter, note, warning | 
| 1352
by Martin Pool - store control weaves in .bzr/, not mixed in with file weaves | 26 | from bzrlib.branch import Branch | 
| 974.1.28
by aaron.bentley at utoronto factored install_revisions out of update_revisions, updated test cases for greedy_fetch | 27 | from bzrlib.progress import ProgressBar | 
| 1231
by Martin Pool - more progress on fetch on top of weaves | 28 | from bzrlib.xml5 import serializer_v5 | 
| 29 | from bzrlib.osutils import sha_string, split_lines | |
| 30 | ||
| 31 | """Copying of history from one branch to another.
 | |
| 32 | ||
| 33 | The basic plan is that every branch knows the history of everything
 | |
| 34 | that has merged into it.  As the first step of a merge, pull, or
 | |
| 35 | branch operation we copy history from the source into the destination
 | |
| 36 | branch.
 | |
| 37 | ||
| 38 | The copying is done in a slightly complicated order.  We don't want to
 | |
| 39 | add a revision to the store until everything it refers to is also
 | |
| 40 | stored, so that if a revision is present we can totally recreate it.
 | |
| 41 | However, we can't know what files are included in a revision until we
 | |
| 42 | read its inventory.  Therefore, we first pull the XML and hold it in
 | |
| 43 | memory until we've updated all of the files referenced.
 | |
| 44 | """
 | |
| 45 | ||
| 46 | # TODO: Avoid repeatedly opening weaves so many times.
 | |
| 974.1.27
by aaron.bentley at utoronto Initial greedy fetch work | 47 | |
| 1238
by Martin Pool - remove a lot of dead code from fetch | 48 | # XXX: This doesn't handle ghost (not present in branch) revisions at
 | 
| 1240
by Martin Pool - clean up fetch code and add progress bar | 49 | # all yet.  I'm not sure they really should be supported.
 | 
| 50 | ||
| 1262
by Martin Pool - fetch should also copy ancestry records | 51 | # NOTE: This doesn't copy revisions which may be present but not
 | 
| 52 | # merged into the last revision.  I'm not sure we want to do that.
 | |
| 1238
by Martin Pool - remove a lot of dead code from fetch | 53 | |
| 54 | # - get a list of revisions that need to be pulled in
 | |
| 55 | # - for each one, pull in that revision file
 | |
| 56 | #   and get the inventory, and store the inventory with right
 | |
| 57 | #   parents.
 | |
| 58 | # - and get the ancestry, and store that with right parents too
 | |
| 59 | # - and keep a note of all file ids and version seen
 | |
| 60 | # - then go through all files; for each one get the weave,
 | |
| 61 | #   and add in all file versions
 | |
| 62 | ||
| 63 | ||
| 1219
by Martin Pool - BROKEN: start refactoring fetch code to work well with weaves | 64 | |
| 1260
by Martin Pool - some updates for fetch/update function | 65 | def greedy_fetch(to_branch, from_branch, revision=None, pb=None): | 
| 1219
by Martin Pool - BROKEN: start refactoring fetch code to work well with weaves | 66 | f = Fetcher(to_branch, from_branch, revision, pb) | 
| 67 | return f.count_copied, f.failed_revisions | |
| 68 | ||
| 69 | ||
| 1265
by Martin Pool - add function-style synonym 'fetch' | 70 | |
| 1219
by Martin Pool - BROKEN: start refactoring fetch code to work well with weaves | 71 | class Fetcher(object): | 
| 1260
by Martin Pool - some updates for fetch/update function | 72 | """Pull revisions and texts from one branch to another. | 
| 73 | ||
| 74 |     This doesn't update the destination's history; that can be done
 | |
| 75 |     separately if desired.  
 | |
| 1231
by Martin Pool - more progress on fetch on top of weaves | 76 | |
| 77 |     revision_limit
 | |
| 78 |         If set, pull only up to this revision_id.
 | |
| 1260
by Martin Pool - some updates for fetch/update function | 79 | |
| 80 |     After running:
 | |
| 81 | ||
| 82 |     last_revision -- if last_revision
 | |
| 83 |         is given it will be that, otherwise the last revision of
 | |
| 84 |         from_branch
 | |
| 85 | ||
| 86 |     count_copied -- number of revisions copied
 | |
| 87 | ||
| 1405
by Robert Collins remove some of the upgrade code that was duplicated with inventory_entry, and give all inventory entries a weave | 88 |     count_weaves -- number of file weaves copied
 | 
| 1260
by Martin Pool - some updates for fetch/update function | 89 |     """
 | 
| 90 | def __init__(self, to_branch, from_branch, last_revision=None, pb=None): | |
| 1393.1.17
by Martin Pool - add assertion to fetch | 91 | if to_branch == from_branch: | 
| 92 | raise Exception("can't fetch from a branch to itself") | |
| 1219
by Martin Pool - BROKEN: start refactoring fetch code to work well with weaves | 93 | self.to_branch = to_branch | 
| 1260
by Martin Pool - some updates for fetch/update function | 94 | self.to_weaves = to_branch.weave_store | 
| 1392
by Robert Collins reinstate testfetch test case | 95 | self.to_control = to_branch.control_weaves | 
| 1219
by Martin Pool - BROKEN: start refactoring fetch code to work well with weaves | 96 | self.from_branch = from_branch | 
| 1260
by Martin Pool - some updates for fetch/update function | 97 | self.from_weaves = from_branch.weave_store | 
| 1392
by Robert Collins reinstate testfetch test case | 98 | self.from_control = from_branch.control_weaves | 
| 1231
by Martin Pool - more progress on fetch on top of weaves | 99 | self.failed_revisions = [] | 
| 100 | self.count_copied = 0 | |
| 1240
by Martin Pool - clean up fetch code and add progress bar | 101 | self.count_total = 0 | 
| 1405
by Robert Collins remove some of the upgrade code that was duplicated with inventory_entry, and give all inventory entries a weave | 102 | self.count_weaves = 0 | 
| 1404
by Robert Collins only pull remote text weaves once per fetch operation | 103 | self.copied_file_ids = set() | 
| 1185.33.55
by Martin Pool [patch] weave fetch optimizations (Goffredo Baroncelli) | 104 | self.file_ids_names = {} | 
| 1219
by Martin Pool - BROKEN: start refactoring fetch code to work well with weaves | 105 | if pb is None: | 
| 106 | self.pb = bzrlib.ui.ui_factory.progress_bar() | |
| 107 | else: | |
| 108 | self.pb = pb | |
| 1437
by Robert Collins lock during fetch, which is a separate code path to the special case of cloning | 109 | self.from_branch.lock_read() | 
| 1392
by Robert Collins reinstate testfetch test case | 110 | try: | 
| 1425
by Robert Collins merge from Aaron - unbreaks open_containing and the fetch progress bar | 111 | self._fetch_revisions(last_revision) | 
| 1185.12.15
by Aaron Bentley Cleared progress bar properly after fetch | 112 | finally: | 
| 1437
by Robert Collins lock during fetch, which is a separate code path to the special case of cloning | 113 | self.from_branch.unlock() | 
| 1185.12.15
by Aaron Bentley Cleared progress bar properly after fetch | 114 | self.pb.clear() | 
| 1231
by Martin Pool - more progress on fetch on top of weaves | 115 | |
| 1425
by Robert Collins merge from Aaron - unbreaks open_containing and the fetch progress bar | 116 | def _fetch_revisions(self, last_revision): | 
| 1185.12.21
by aaron.bentley at utoronto Cleaned up Fetcher._find_last_revision | 117 | self.last_revision = self._find_last_revision(last_revision) | 
| 1425
by Robert Collins merge from Aaron - unbreaks open_containing and the fetch progress bar | 118 | mutter('fetch up to rev {%s}', self.last_revision) | 
| 1440
by Robert Collins further tuning of pull, do not do a local merge or fetch at all, if the remote branch is no newer than we are | 119 | if (self.last_revision is not None and | 
| 120 | self.to_branch.has_revision(self.last_revision)): | |
| 121 |             return
 | |
| 1417.1.13
by Robert Collins do not download remote ancestry.weave if the target revision we are stopping at is in our local store | 122 | try: | 
| 1425
by Robert Collins merge from Aaron - unbreaks open_containing and the fetch progress bar | 123 | revs_to_fetch = self._compare_ancestries() | 
| 124 | except WeaveError: | |
| 125 | raise InstallFailed([self.last_revision]) | |
| 126 | self._copy_revisions(revs_to_fetch) | |
| 127 | self.new_ancestry = revs_to_fetch | |
| 1240
by Martin Pool - clean up fetch code and add progress bar | 128 | |
| 1260
by Martin Pool - some updates for fetch/update function | 129 | def _find_last_revision(self, last_revision): | 
| 1240
by Martin Pool - clean up fetch code and add progress bar | 130 | """Find the limiting source revision. | 
| 131 | ||
| 132 |         Every ancestor of that revision will be merged across.
 | |
| 133 | ||
| 134 |         Returns the revision_id, or returns None if there's no history
 | |
| 135 |         in the source branch."""
 | |
| 1185.12.21
by aaron.bentley at utoronto Cleaned up Fetcher._find_last_revision | 136 | if last_revision: | 
| 137 | return last_revision | |
| 1240
by Martin Pool - clean up fetch code and add progress bar | 138 | self.pb.update('get source history') | 
| 139 | from_history = self.from_branch.revision_history() | |
| 140 | self.pb.update('get destination history') | |
| 1185.12.21
by aaron.bentley at utoronto Cleaned up Fetcher._find_last_revision | 141 | if from_history: | 
| 1240
by Martin Pool - clean up fetch code and add progress bar | 142 | return from_history[-1] | 
| 143 | else: | |
| 144 | return None # no history in the source branch | |
| 1231
by Martin Pool - more progress on fetch on top of weaves | 145 | |
| 146 | ||
| 147 | def _compare_ancestries(self): | |
| 148 | """Get a list of revisions that must be copied. | |
| 149 | ||
| 150 |         That is, every revision that's in the ancestry of the source
 | |
| 151 |         branch and not in the destination branch."""
 | |
| 1240
by Martin Pool - clean up fetch code and add progress bar | 152 | self.pb.update('get source ancestry') | 
| 1260
by Martin Pool - some updates for fetch/update function | 153 | self.from_ancestry = self.from_branch.get_ancestry(self.last_revision) | 
| 1240
by Martin Pool - clean up fetch code and add progress bar | 154 | |
| 1241
by Martin Pool - rename last_patch to last_revision | 155 | dest_last_rev = self.to_branch.last_revision() | 
| 1240
by Martin Pool - clean up fetch code and add progress bar | 156 | self.pb.update('get destination ancestry') | 
| 157 | if dest_last_rev: | |
| 158 | dest_ancestry = self.to_branch.get_ancestry(dest_last_rev) | |
| 159 | else: | |
| 160 | dest_ancestry = [] | |
| 161 | ss = set(dest_ancestry) | |
| 1231
by Martin Pool - more progress on fetch on top of weaves | 162 | to_fetch = [] | 
| 163 | for rev_id in self.from_ancestry: | |
| 164 | if rev_id not in ss: | |
| 165 | to_fetch.append(rev_id) | |
| 1219
by Martin Pool - BROKEN: start refactoring fetch code to work well with weaves | 166 | mutter('need to get revision {%s}', rev_id) | 
| 1231
by Martin Pool - more progress on fetch on top of weaves | 167 | mutter('need to get %d revisions in total', len(to_fetch)) | 
| 1240
by Martin Pool - clean up fetch code and add progress bar | 168 | self.count_total = len(to_fetch) | 
| 1231
by Martin Pool - more progress on fetch on top of weaves | 169 | return to_fetch | 
| 170 | ||
| 171 | def _copy_revisions(self, revs_to_fetch): | |
| 1240
by Martin Pool - clean up fetch code and add progress bar | 172 | i = 0 | 
| 1231
by Martin Pool - more progress on fetch on top of weaves | 173 | for rev_id in revs_to_fetch: | 
| 1261
by Martin Pool - new method Branch.has_revision | 174 | i += 1 | 
| 1390
by Robert Collins pair programming worx... merge integration and weave | 175 | if rev_id is None: | 
| 176 |                 continue
 | |
| 1261
by Martin Pool - new method Branch.has_revision | 177 | if self.to_branch.has_revision(rev_id): | 
| 178 |                 continue
 | |
| 1185.33.78
by Martin Pool Change fetch status message to "copying revision" so it makes sense when pushing. | 179 | self.pb.update('copy revision', i, self.count_total) | 
| 1231
by Martin Pool - more progress on fetch on top of weaves | 180 | self._copy_one_revision(rev_id) | 
| 1260
by Martin Pool - some updates for fetch/update function | 181 | self.count_copied += 1 | 
| 1231
by Martin Pool - more progress on fetch on top of weaves | 182 | |
| 183 | ||
| 184 | def _copy_one_revision(self, rev_id): | |
| 185 | """Copy revision and everything referenced by it.""" | |
| 186 | mutter('copying revision {%s}', rev_id) | |
| 187 | rev_xml = self.from_branch.get_revision_xml(rev_id) | |
| 188 | inv_xml = self.from_branch.get_inventory_xml(rev_id) | |
| 189 | rev = serializer_v5.read_revision_from_string(rev_xml) | |
| 190 | inv = serializer_v5.read_inventory_from_string(inv_xml) | |
| 191 | assert rev.revision_id == rev_id | |
| 192 | assert rev.inventory_sha1 == sha_string(inv_xml) | |
| 193 | mutter(' commiter %s, %d parents', | |
| 194 | rev.committer, | |
| 1313
by Martin Pool - rename to Revision.parent_ids to avoid confusion with old usage | 195 | len(rev.parent_ids)) | 
| 1231
by Martin Pool - more progress on fetch on top of weaves | 196 | self._copy_new_texts(rev_id, inv) | 
| 1092.2.26
by Robert Collins fetch should work with ghosts | 197 | parents = rev.parent_ids | 
| 1480
by Robert Collins BUGFIX: fetch was not skipping all missing parents for inventory insertion | 198 | new_parents = copy(parents) | 
| 1092.2.26
by Robert Collins fetch should work with ghosts | 199 | for parent in parents: | 
| 200 | if not self.to_branch.has_revision(parent): | |
| 1480
by Robert Collins BUGFIX: fetch was not skipping all missing parents for inventory insertion | 201 | new_parents.pop(new_parents.index(parent)) | 
| 202 | self._copy_inventory(rev_id, inv_xml, new_parents) | |
| 1262
by Martin Pool - fetch should also copy ancestry records | 203 | self.to_branch.revision_store.add(StringIO(rev_xml), rev_id) | 
| 1404
by Robert Collins only pull remote text weaves once per fetch operation | 204 | mutter('copied revision %s', rev_id) | 
| 1262
by Martin Pool - fetch should also copy ancestry records | 205 | |
| 206 | def _copy_inventory(self, rev_id, inv_xml, parent_ids): | |
| 1352
by Martin Pool - store control weaves in .bzr/, not mixed in with file weaves | 207 | self.to_control.add_text('inventory', rev_id, | 
| 1417.1.8
by Robert Collins use transactions in the weave store interface, which enables caching for log | 208 | split_lines(inv_xml), parent_ids, | 
| 209 | self.to_branch.get_transaction()) | |
| 1262
by Martin Pool - fetch should also copy ancestry records | 210 | |
| 1231
by Martin Pool - more progress on fetch on top of weaves | 211 | def _copy_new_texts(self, rev_id, inv): | 
| 212 | """Copy any new texts occuring in this revision.""" | |
| 213 |         # TODO: Rather than writing out weaves every time, hold them
 | |
| 214 |         # in memory until everything's done?  But this way is nicer
 | |
| 215 |         # if it's interrupted.
 | |
| 216 | for path, ie in inv.iter_entries(): | |
| 1185.35.42
by Aaron Bentley Fixed fetch to be safer wrt ghosts and corrupt branches | 217 | self._copy_one_weave(rev_id, ie.file_id, ie.revision) | 
| 1405
by Robert Collins remove some of the upgrade code that was duplicated with inventory_entry, and give all inventory entries a weave | 218 | |
| 1185.35.42
by Aaron Bentley Fixed fetch to be safer wrt ghosts and corrupt branches | 219 | def _copy_one_weave(self, rev_id, file_id, text_revision): | 
| 220 | """Copy one file weave, esuring the result contains text_revision.""" | |
| 1185.33.55
by Martin Pool [patch] weave fetch optimizations (Goffredo Baroncelli) | 221 |         # check if the revision is already there
 | 
| 222 | if file_id in self.file_ids_names.keys( ) and \ | |
| 223 | text_revision in self.file_ids_names[file_id]: | |
| 224 |                 return        
 | |
| 1185.35.42
by Aaron Bentley Fixed fetch to be safer wrt ghosts and corrupt branches | 225 | to_weave = self.to_weaves.get_weave_or_empty(file_id, | 
| 226 | self.to_branch.get_transaction()) | |
| 1185.33.55
by Martin Pool [patch] weave fetch optimizations (Goffredo Baroncelli) | 227 | if not file_id in self.file_ids_names.keys( ): | 
| 228 | self.file_ids_names[file_id] = to_weave.names( ) | |
| 1185.35.42
by Aaron Bentley Fixed fetch to be safer wrt ghosts and corrupt branches | 229 | if text_revision in to_weave: | 
| 1404
by Robert Collins only pull remote text weaves once per fetch operation | 230 |             return
 | 
| 1185.1.51
by Robert Collins merge in reweave support | 231 | from_weave = self.from_weaves.get_weave(file_id, | 
| 1417.1.8
by Robert Collins use transactions in the weave store interface, which enables caching for log | 232 | self.from_branch.get_transaction()) | 
| 1185.35.42
by Aaron Bentley Fixed fetch to be safer wrt ghosts and corrupt branches | 233 | if text_revision not in from_weave: | 
| 234 | raise MissingText(self.from_branch, text_revision, file_id) | |
| 235 | mutter('copy file {%s} modified in {%s}', file_id, rev_id) | |
| 1185.33.55
by Martin Pool [patch] weave fetch optimizations (Goffredo Baroncelli) | 236 | |
| 237 | if to_weave.numversions() > 0: | |
| 238 |             # destination has contents, must merge
 | |
| 239 | try: | |
| 240 | to_weave.join(from_weave) | |
| 241 | except errors.WeaveParentMismatch: | |
| 242 | to_weave.reweave(from_weave) | |
| 243 | else: | |
| 244 |             # destination is empty, just replace it
 | |
| 245 | to_weave = from_weave.copy( ) | |
| 1417.1.8
by Robert Collins use transactions in the weave store interface, which enables caching for log | 246 | self.to_weaves.put_weave(file_id, to_weave, | 
| 247 | self.to_branch.get_transaction()) | |
| 1405
by Robert Collins remove some of the upgrade code that was duplicated with inventory_entry, and give all inventory entries a weave | 248 | self.count_weaves += 1 | 
| 1404
by Robert Collins only pull remote text weaves once per fetch operation | 249 | self.copied_file_ids.add(file_id) | 
| 1185.33.55
by Martin Pool [patch] weave fetch optimizations (Goffredo Baroncelli) | 250 | self.file_ids_names[file_id] = to_weave.names() | 
| 1404
by Robert Collins only pull remote text weaves once per fetch operation | 251 | mutter('copied file {%s}', file_id) | 
| 1265
by Martin Pool - add function-style synonym 'fetch' | 252 | |
| 253 | ||
| 254 | fetch = Fetcher |