14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
from cStringIO import StringIO
22
import bzrlib.errors as errors
23
from bzrlib.errors import (InstallFailed, NoSuchRevision, WeaveError,
25
from bzrlib.trace import mutter, note, warning
26
from bzrlib.branch import Branch
27
from bzrlib.progress import ProgressBar
28
from bzrlib.xml5 import serializer_v5
29
from bzrlib.osutils import sha_string, split_lines
31
18
"""Copying of history from one branch to another.
43
30
memory until we've updated all of the files referenced.
34
import bzrlib.errors as errors
35
from bzrlib.errors import (InstallFailed, NoSuchRevision, WeaveError,
37
from bzrlib.trace import mutter
38
from bzrlib.progress import ProgressBar
39
from bzrlib.revision import NULL_REVISION
40
from bzrlib.symbol_versioning import *
46
43
# TODO: Avoid repeatedly opening weaves so many times.
48
45
# XXX: This doesn't handle ghost (not present in branch) revisions at
61
58
# and add in all file versions
61
@deprecated_function(zero_eight)
65
62
def greedy_fetch(to_branch, from_branch, revision=None, pb=None):
63
"""Legacy API, please see branch.fetch(from_branch, last_revision, pb)."""
66
64
f = Fetcher(to_branch, from_branch, revision, pb)
67
65
return f.count_copied, f.failed_revisions
71
class Fetcher(object):
72
"""Pull revisions and texts from one branch to another.
74
This doesn't update the destination's history; that can be done
75
separately if desired.
78
If set, pull only up to this revision_id.
82
last_revision -- if last_revision
83
is given it will be that, otherwise the last revision of
70
class RepoFetcher(object):
71
"""Pull revisions and texts from one repository to another.
74
if set, try to limit to the data this revision references.
86
77
count_copied -- number of revisions copied
88
count_weaves -- number of file weaves copied
79
This should not be used directory, its essential a object to encapsulate
80
the logic in InterRepository.fetch().
90
def __init__(self, to_branch, from_branch, last_revision=None, pb=None):
91
if to_branch.base == from_branch.base:
92
raise Exception("can't fetch from a branch to itself %s, %s" %
93
(from_branch.base, to_branch.base))
95
self.to_branch = to_branch
96
self.from_branch = from_branch
82
def __init__(self, to_repository, from_repository, last_revision=None, pb=None):
84
self.failed_revisions = []
86
if to_repository.bzrdir.transport.base == from_repository.bzrdir.transport.base:
87
# check that last_revision is in 'from' and then return a no-operation.
88
if last_revision not in (None, NULL_REVISION):
89
from_repository.get_revision(last_revision)
91
self.to_repository = to_repository
92
self.from_repository = from_repository
93
# must not mutate self._last_revision as its potentially a shared instance
97
94
self._last_revision = last_revision
99
96
self.pb = bzrlib.ui.ui_factory.progress_bar()
102
self.from_branch.lock_read()
99
self.from_repository.lock_read()
104
self.to_branch.lock_write()
101
self.to_repository.lock_write()
108
self.to_branch.unlock()
105
self.to_repository.unlock()
110
self.from_branch.unlock()
107
self.from_repository.unlock()
112
109
def __fetch(self):
113
110
"""Primary worker function.
115
112
This initialises all the needed variables, and then fetches the
116
113
requested revisions, finally clearing the progress bar.
118
self.to_repository = self.to_branch.repository
119
115
self.to_weaves = self.to_repository.weave_store
120
116
self.to_control = self.to_repository.control_weaves
121
self.from_repository = self.from_branch.repository
122
117
self.from_weaves = self.from_repository.weave_store
123
118
self.from_control = self.from_repository.control_weaves
124
self.failed_revisions = []
125
self.count_copied = 0
126
119
self.count_total = 0
127
self.count_weaves = 0
128
self.copied_file_ids = set()
129
120
self.file_ids_names = {}
131
122
revs = self._revids_to_fetch()
141
132
def _revids_to_fetch(self):
142
self._find_last_revision()
133
self.pb.update('get destination history')
143
134
mutter('fetch up to rev {%s}', self._last_revision)
144
if (self._last_revision is not None and
135
if self._last_revision is NULL_REVISION:
136
# explicit limit of no revisions needed
138
if (self._last_revision != None and
145
139
self.to_repository.has_revision(self._last_revision)):
148
branch_from_revs = set(self.from_repository.get_ancestry(self._last_revision))
143
return self.to_repository.missing_revision_ids(self.from_repository,
145
except errors.NoSuchRevision:
150
146
raise InstallFailed([self._last_revision])
152
self.dest_last_rev = self.to_branch.last_revision()
153
branch_to_revs = set(self.to_repository.get_ancestry(self.dest_last_rev))
155
return branch_from_revs.difference(branch_to_revs)
157
148
def _fetch_revision_texts(self, revs):
158
149
self.to_repository.revision_store.copy_multi(
159
self.from_repository.revision_store, revs)
150
self.from_repository.revision_store,
161
154
def _fetch_weave_texts(self, revs):
162
file_ids = self.from_branch.fileid_involved_by_set(revs)
155
file_ids = self.from_repository.fileid_involved_by_set(revs)
164
157
num_file_ids = len(file_ids)
165
158
for file_id in file_ids:
166
self.pb.update("merge weave merge", count, num_file_ids)
159
self.pb.update("merge weaves", count, num_file_ids)
168
161
to_weave = self.to_weaves.get_weave_or_empty(file_id,
169
self.to_branch.get_transaction())
162
self.to_repository.get_transaction())
170
163
from_weave = self.from_weaves.get_weave(file_id,
171
self.from_branch.get_transaction())
164
self.from_repository.get_transaction())
173
166
if to_weave.numversions() > 0:
174
167
# destination has contents, must merge
191
183
to_weave = self.to_repository.get_inventory_weave()
192
184
self.pb.update("inventory fetch", 1, 2)
193
185
to_weave = self.to_control.get_weave('inventory',
194
self.to_branch.get_transaction())
186
self.to_repository.get_transaction())
195
187
self.pb.update("inventory fetch", 2, 2)
197
189
if to_weave.numversions() > 0:
205
197
to_weave = from_weave.copy()
207
199
self.to_control.put_weave('inventory', to_weave,
208
self.to_branch.get_transaction())
200
self.to_repository.get_transaction())
212
def _find_last_revision(self):
213
"""Find the limiting source revision.
215
Every ancestor of that revision will be merged across.
217
Returns the revision_id, or returns None if there's no history
218
in the source branch."""
219
if self._last_revision:
221
self.pb.update('get source history')
222
from_history = self.from_branch.revision_history()
223
self.pb.update('get destination history')
225
self._last_revision = from_history[-1]
227
# no history in the source branch
228
self._last_revision = None
205
class Fetcher(object):
206
"""Backwards compatability glue for branch.fetch()."""
208
@deprecated_method(zero_eight)
209
def __init__(self, to_branch, from_branch, last_revision=None, pb=None):
210
"""Please see branch.fetch()."""
211
to_branch.fetch(from_branch, last_revision, pb)