/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.64.1 by Ian Clatworthy
1st cut: gfi parser + --info processing method
1
# Copyright (C) 2008 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
16
17
"""Import processor that supports all Bazaar repository formats."""
18
19
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
20
import time
0.64.5 by Ian Clatworthy
first cut at generic processing method
21
from bzrlib import (
0.64.37 by Ian Clatworthy
create branches as required
22
    bzrdir,
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
23
    delta,
0.64.5 by Ian Clatworthy
first cut at generic processing method
24
    errors,
25
    osutils,
0.64.26 by Ian Clatworthy
more progress reporting tweaks
26
    progress,
0.64.5 by Ian Clatworthy
first cut at generic processing method
27
    )
0.64.51 by Ian Clatworthy
disable autopacking
28
from bzrlib.repofmt import pack_repo
0.78.4 by Ian Clatworthy
move GenericBranchUpdater into its own module
29
from bzrlib.trace import note
0.64.24 by Ian Clatworthy
smart blob caching using analysis done by --info
30
import bzrlib.util.configobj.configobj as configobj
0.64.5 by Ian Clatworthy
first cut at generic processing method
31
from bzrlib.plugins.fastimport import (
0.78.4 by Ian Clatworthy
move GenericBranchUpdater into its own module
32
    branch_updater,
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
33
    bzr_commit_handler,
0.78.3 by Ian Clatworthy
move GenericCacheManager into its own module
34
    cache_manager,
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
35
    errors as plugin_errors,
0.64.31 by Ian Clatworthy
fix branch updating for the single branch case
36
    helpers,
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
37
    idmapfile,
0.78.5 by Ian Clatworthy
move import/export of marks into a module
38
    marks_file,
0.64.5 by Ian Clatworthy
first cut at generic processing method
39
    processor,
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
40
    revision_store,
0.64.5 by Ian Clatworthy
first cut at generic processing method
41
    )
0.64.1 by Ian Clatworthy
1st cut: gfi parser + --info processing method
42
43
0.64.41 by Ian Clatworthy
update multiple working trees if requested
44
# How many commits before automatically reporting progress
45
_DEFAULT_AUTO_PROGRESS = 1000
46
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
47
# How many commits before automatically checkpointing
48
_DEFAULT_AUTO_CHECKPOINT = 10000
49
0.64.44 by Ian Clatworthy
smart caching of serialised inventories
50
# How many inventories to cache
51
_DEFAULT_INV_CACHE_SIZE = 10
52
0.64.41 by Ian Clatworthy
update multiple working trees if requested
53
0.64.1 by Ian Clatworthy
1st cut: gfi parser + --info processing method
54
class GenericProcessor(processor.ImportProcessor):
55
    """An import processor that handles basic imports.
56
57
    Current features supported:
58
0.64.16 by Ian Clatworthy
safe processing tweaks
59
    * blobs are cached in memory
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
60
    * files and symlinks commits are supported
61
    * checkpoints automatically happen at a configurable frequency
62
      over and above the stream requested checkpoints
63
    * timestamped progress reporting, both automatic and stream requested
0.64.1 by Ian Clatworthy
1st cut: gfi parser + --info processing method
64
    * some basic statistics are dumped on completion.
0.64.24 by Ian Clatworthy
smart blob caching using analysis done by --info
65
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
66
    At checkpoints and on completion, the commit-id -> revision-id map is
67
    saved to a file called 'fastimport-id-map'. If the import crashes
68
    or is interrupted, it can be started again and this file will be
69
    used to skip over already loaded revisions. The format of each line
70
    is "commit-id revision-id" so commit-ids cannot include spaces.
71
0.64.24 by Ian Clatworthy
smart blob caching using analysis done by --info
72
    Here are the supported parameters:
73
0.64.38 by Ian Clatworthy
clean-up doc ready for initial release
74
    * info - name of a hints file holding the analysis generated
75
      by running the fast-import-info processor in verbose mode. When
0.64.33 by Ian Clatworthy
make tree updating optional and minor UI improvements
76
      importing large repositories, this parameter is needed so
77
      that the importer knows what blobs to intelligently cache.
78
0.64.41 by Ian Clatworthy
update multiple working trees if requested
79
    * trees - update the working trees before completing.
0.64.33 by Ian Clatworthy
make tree updating optional and minor UI improvements
80
      By default, the importer updates the repository
81
      and branches and the user needs to run 'bzr update' for the
0.64.41 by Ian Clatworthy
update multiple working trees if requested
82
      branches of interest afterwards.
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
83
84
    * checkpoint - automatically checkpoint every n commits over and
85
      above any checkpoints contained in the import stream.
86
      The default is 10000.
87
0.64.44 by Ian Clatworthy
smart caching of serialised inventories
88
    * count - only import this many commits then exit. If not set
89
      or negative, all commits are imported.
90
    
91
    * inv-cache - number of inventories to cache.
92
      If not set, the default is 10.
0.64.47 by Ian Clatworthy
add option for enabling experimental stuff
93
94
    * experimental - enable experimental mode, i.e. use features
95
      not yet fully tested.
0.64.82 by Ian Clatworthy
Merge Pieter de Bie's export-fixes branch
96
97
    * import-marks - name of file to read to load mark information from
98
99
    * export-marks - name of file to write to save mark information to
0.64.1 by Ian Clatworthy
1st cut: gfi parser + --info processing method
100
    """
101
0.64.47 by Ian Clatworthy
add option for enabling experimental stuff
102
    known_params = [
103
        'info',
104
        'trees',
105
        'checkpoint',
106
        'count',
107
        'inv-cache',
108
        'experimental',
0.68.7 by Pieter de Bie
Add importing and exporting of marks to bzr-fastimport
109
        'import-marks',
110
        'export-marks',
0.64.47 by Ian Clatworthy
add option for enabling experimental stuff
111
        ]
0.64.33 by Ian Clatworthy
make tree updating optional and minor UI improvements
112
0.64.1 by Ian Clatworthy
1st cut: gfi parser + --info processing method
113
    def pre_process(self):
0.64.26 by Ian Clatworthy
more progress reporting tweaks
114
        self._start_time = time.time()
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
115
        self._load_info_and_params()
0.78.3 by Ian Clatworthy
move GenericCacheManager into its own module
116
        self.cache_mgr = cache_manager.CacheManager(self.info, self.verbose,
0.64.44 by Ian Clatworthy
smart caching of serialised inventories
117
            self.inventory_cache_size)
0.68.7 by Pieter de Bie
Add importing and exporting of marks to bzr-fastimport
118
        
0.64.82 by Ian Clatworthy
Merge Pieter de Bie's export-fixes branch
119
        if self.params.get("import-marks") is not None:
0.79.2 by Ian Clatworthy
extend & use marks_file API
120
            mark_info = marks_file.import_marks(self.params.get("import-marks"))
121
            if mark_info is not None:
122
                self.cache_mgr.revision_ids = mark_info[0]
0.68.7 by Pieter de Bie
Add importing and exporting of marks to bzr-fastimport
123
            self.skip_total = False
124
            self.first_incremental_commit = True
125
        else:
126
            self.first_incremental_commit = False
127
            self.skip_total = self._init_id_map()
128
            if self.skip_total:
129
                self.note("Found %d commits already loaded - "
130
                    "skipping over these ...", self.skip_total)
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
131
        self._revision_count = 0
132
133
        # mapping of tag name to revision_id
134
        self.tags = {}
135
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
136
        # Create the revision store to use for committing, if any
137
        self.rev_store = self._revision_store_factory()
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
138
0.64.51 by Ian Clatworthy
disable autopacking
139
        # Disable autopacking if the repo format supports it.
140
        # THIS IS A HACK - there is no sanctioned way of doing this yet.
141
        if isinstance(self.repo, pack_repo.KnitPackRepository):
142
            self._original_max_pack_count = \
143
                self.repo._pack_collection._max_pack_count
144
            def _max_pack_count_for_import(total_revisions):
145
                return total_revisions + 1
146
            self.repo._pack_collection._max_pack_count = \
147
                _max_pack_count_for_import
148
        else:
149
            self._original_max_pack_count = None
150
            
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
151
        # Create a write group. This is committed at the end of the import.
152
        # Checkpointing closes the current one and starts a new one.
153
        self.repo.start_write_group()
154
155
    def _load_info_and_params(self):
0.64.52 by Ian Clatworthy
switch on experimental mode by default
156
        self._experimental = bool(self.params.get('experimental', False))
0.64.47 by Ian Clatworthy
add option for enabling experimental stuff
157
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
158
        # This is currently hard-coded but might be configurable via
159
        # parameters one day if that's needed
160
        repo_transport = self.repo.control_files._transport
161
        self.id_map_path = repo_transport.local_abspath("fastimport-id-map")
162
0.64.24 by Ian Clatworthy
smart blob caching using analysis done by --info
163
        # Load the info file, if any
164
        info_path = self.params.get('info')
165
        if info_path is not None:
166
            self.info = configobj.ConfigObj(info_path)
167
        else:
168
            self.info = None
169
0.84.4 by Ian Clatworthy
improved-but-not-yet-working CHKInventory support
170
        # Decide which CommitHandler to use
171
        if hasattr(self.repo, 'chk_bytes'):
172
            self.commit_handler_factory = \
0.84.7 by Ian Clatworthy
CHKInventory support for non rich-root repos working, for simple imports at least
173
                bzr_commit_handler.CHKInventoryCommitHandler
0.84.4 by Ian Clatworthy
improved-but-not-yet-working CHKInventory support
174
        else:
175
            self.commit_handler_factory = \
176
                bzr_commit_handler.InventoryCommitHandler
177
0.64.41 by Ian Clatworthy
update multiple working trees if requested
178
        # Decide how often to automatically report progress
179
        # (not a parameter yet)
180
        self.progress_every = _DEFAULT_AUTO_PROGRESS
181
        if self.verbose:
182
            self.progress_every = self.progress_every / 10
183
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
184
        # Decide how often to automatically checkpoint
185
        self.checkpoint_every = int(self.params.get('checkpoint',
186
            _DEFAULT_AUTO_CHECKPOINT))
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
187
0.64.44 by Ian Clatworthy
smart caching of serialised inventories
188
        # Decide how big to make the inventory cache
189
        self.inventory_cache_size = int(self.params.get('inv-cache',
190
            _DEFAULT_INV_CACHE_SIZE))
191
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
192
        # Find the maximum number of commits to import (None means all)
193
        # and prepare progress reporting. Just in case the info file
194
        # has an outdated count of commits, we store the max counts
195
        # at which we need to terminate separately to the total used
196
        # for progress tracking.
197
        try:
198
            self.max_commits = int(self.params['count'])
0.64.38 by Ian Clatworthy
clean-up doc ready for initial release
199
            if self.max_commits < 0:
200
                self.max_commits = None
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
201
        except KeyError:
202
            self.max_commits = None
0.64.25 by Ian Clatworthy
slightly better progress reporting
203
        if self.info is not None:
204
            self.total_commits = int(self.info['Command counts']['commit'])
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
205
            if (self.max_commits is not None and
206
                self.total_commits > self.max_commits):
207
                self.total_commits = self.max_commits
0.64.25 by Ian Clatworthy
slightly better progress reporting
208
        else:
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
209
            self.total_commits = self.max_commits
0.64.25 by Ian Clatworthy
slightly better progress reporting
210
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
211
    def _revision_store_factory(self):
212
        """Make a RevisionStore based on what the repository supports."""
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
213
        new_repo_api = hasattr(self.repo, 'revisions')
214
        if new_repo_api:
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
215
            return revision_store.RevisionStore2(self.repo)
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
216
        elif not self._experimental:
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
217
            return revision_store.RevisionStore1(self.repo)
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
218
        else:
219
            def fulltext_when(count):
220
                total = self.total_commits
221
                if total is not None and count == total:
222
                    fulltext = True
223
                else:
224
                    # Create an inventory fulltext every 200 revisions
225
                    fulltext = count % 200 == 0
226
                if fulltext:
227
                    self.note("%d commits - storing inventory as full-text",
228
                        count)
229
                return fulltext
230
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
231
            return revision_store.ImportRevisionStore1(
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
232
                self.repo, self.inventory_cache_size,
233
                fulltext_when=fulltext_when)
234
0.64.27 by Ian Clatworthy
1st cut at performance tuning
235
    def _process(self, command_iter):
236
        # if anything goes wrong, abort the write group if any
237
        try:
238
            processor.ImportProcessor._process(self, command_iter)
239
        except:
240
            if self.repo is not None and self.repo.is_in_write_group():
241
                self.repo.abort_write_group()
242
            raise
243
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
244
    def post_process(self):
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
245
        # Commit the current write group and checkpoint the id map
0.64.27 by Ian Clatworthy
1st cut at performance tuning
246
        self.repo.commit_write_group()
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
247
        self._save_id_map()
0.64.27 by Ian Clatworthy
1st cut at performance tuning
248
0.64.82 by Ian Clatworthy
Merge Pieter de Bie's export-fixes branch
249
        if self.params.get("export-marks") is not None:
0.78.5 by Ian Clatworthy
move import/export of marks into a module
250
            marks_file.export_marks(self.params.get("export-marks"),
251
                self.cache_mgr.revision_ids)
0.68.7 by Pieter de Bie
Add importing and exporting of marks to bzr-fastimport
252
0.64.31 by Ian Clatworthy
fix branch updating for the single branch case
253
        # Update the branches
254
        self.note("Updating branch information ...")
0.78.4 by Ian Clatworthy
move GenericBranchUpdater into its own module
255
        updater = branch_updater.BranchUpdater(self.repo, self.branch,
256
            self.cache_mgr, helpers.invert_dictset(self.cache_mgr.heads),
0.64.64 by Ian Clatworthy
save tags known about in each branch
257
            self.cache_mgr.last_ref, self.tags)
0.64.34 by Ian Clatworthy
report lost branches
258
        branches_updated, branches_lost = updater.update()
259
        self._branch_count = len(branches_updated)
260
261
        # Tell the user about branches that were not created
262
        if branches_lost:
0.64.37 by Ian Clatworthy
create branches as required
263
            if not self.repo.is_shared():
264
                self.warning("Cannot import multiple branches into "
265
                    "an unshared repository")
266
            self.warning("Not creating branches for these head revisions:")
0.64.34 by Ian Clatworthy
report lost branches
267
            for lost_info in branches_lost:
268
                head_revision = lost_info[1]
269
                branch_name = lost_info[0]
0.64.67 by James Westby
Add support for -Dfast-import.
270
                self.note("\t %s = %s", head_revision, branch_name)
0.64.34 by Ian Clatworthy
report lost branches
271
272
        # Update the working trees as requested and dump stats
0.64.33 by Ian Clatworthy
make tree updating optional and minor UI improvements
273
        self._tree_count = 0
0.64.34 by Ian Clatworthy
report lost branches
274
        remind_about_update = True
0.64.54 by Ian Clatworthy
handle existing branches and only count the branches really updated
275
        if self._branch_count == 0:
276
            self.note("no branches to update")
277
            self.note("no working trees to update")
278
            remind_about_update = False
279
        elif self.params.get('trees', False):
0.64.41 by Ian Clatworthy
update multiple working trees if requested
280
            trees = self._get_working_trees(branches_updated)
281
            if trees:
282
                self.note("Updating the working trees ...")
0.64.33 by Ian Clatworthy
make tree updating optional and minor UI improvements
283
                if self.verbose:
284
                    report = delta._ChangeReporter()
285
                else:
286
                    reporter = None
0.64.41 by Ian Clatworthy
update multiple working trees if requested
287
                for wt in trees:
288
                    wt.update(reporter)
289
                    self._tree_count += 1
0.64.34 by Ian Clatworthy
report lost branches
290
                remind_about_update = False
0.64.41 by Ian Clatworthy
update multiple working trees if requested
291
            else:
292
                self.warning("No working trees available to update")
0.64.31 by Ian Clatworthy
fix branch updating for the single branch case
293
        self.dump_stats()
0.64.51 by Ian Clatworthy
disable autopacking
294
295
        # Finish up by telling the user what to do next.
296
        if self._original_max_pack_count:
297
            # We earlier disabled autopacking, creating one pack every
0.64.75 by Ian Clatworthy
if checkpointed, pack repository and delete obsolete_packs
298
            # checkpoint instead. We now pack the repository to optimise
299
            # how data is stored.
300
            if self._revision_count > self.checkpoint_every:
301
                self.note("Packing repository ...")
302
                self.repo.pack()
303
                # To be conservative, packing puts the old packs and
304
                # indices in obsolete_packs. We err on the side of
305
                # optimism and clear out that directory to save space.
306
                self.note("Removing obsolete packs ...")
307
                # TODO: Use a public API for this once one exists
308
                repo_transport = self.repo._pack_collection.transport
309
                repo_transport.clone('obsolete_packs').delete_multi(
310
                    repo_transport.list_dir('obsolete_packs'))
0.64.34 by Ian Clatworthy
report lost branches
311
        if remind_about_update:
0.64.75 by Ian Clatworthy
if checkpointed, pack repository and delete obsolete_packs
312
            # This message is explicitly not timestamped.
0.64.51 by Ian Clatworthy
disable autopacking
313
            note("To refresh the working tree for a branch, "
314
                "use 'bzr update'.")
0.64.41 by Ian Clatworthy
update multiple working trees if requested
315
316
    def _get_working_trees(self, branches):
317
        """Get the working trees for branches in the repository."""
318
        result = []
319
        wt_expected = self.repo.make_working_trees()
320
        for br in branches:
321
            if br == self.branch and br is not None:
322
                wt = self.working_tree
323
            elif wt_expected:
324
                try:
325
                    wt = br.bzrdir.open_workingtree()
326
                except errors.NoWorkingTree:
327
                    self.warning("No working tree for branch %s", br)
328
                    continue
329
            else:
330
                continue
331
            result.append(wt)
332
        return result
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
333
334
    def dump_stats(self):
0.64.33 by Ian Clatworthy
make tree updating optional and minor UI improvements
335
        time_required = progress.str_tdelta(time.time() - self._start_time)
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
336
        rc = self._revision_count - self.skip_total
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
337
        bc = self._branch_count
0.64.33 by Ian Clatworthy
make tree updating optional and minor UI improvements
338
        wtc = self._tree_count
339
        self.note("Imported %d %s, updating %d %s and %d %s in %s",
0.64.32 by Ian Clatworthy
move single_plural into helpers
340
            rc, helpers.single_plural(rc, "revision", "revisions"),
341
            bc, helpers.single_plural(bc, "branch", "branches"),
0.64.33 by Ian Clatworthy
make tree updating optional and minor UI improvements
342
            wtc, helpers.single_plural(wtc, "tree", "trees"),
343
            time_required)
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
344
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
345
    def _init_id_map(self):
346
        """Load the id-map and check it matches the repository.
347
        
348
        :return: the number of entries in the map
349
        """
350
        # Currently, we just check the size. In the future, we might
351
        # decide to be more paranoid and check that the revision-ids
352
        # are identical as well.
353
        self.cache_mgr.revision_ids, known = idmapfile.load_id_map(
354
            self.id_map_path)
355
        existing_count = len(self.repo.all_revision_ids())
0.64.106 by Ian Clatworthy
let the id-map file have more revisions than the repository
356
        if existing_count < known:
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
357
            raise plugin_errors.BadRepositorySize(known, existing_count)
358
        return known
359
360
    def _save_id_map(self):
361
        """Save the id-map."""
362
        # Save the whole lot every time. If this proves a problem, we can
363
        # change to 'append just the new ones' at a later time.
364
        idmapfile.save_id_map(self.id_map_path, self.cache_mgr.revision_ids)
365
0.64.5 by Ian Clatworthy
first cut at generic processing method
366
    def blob_handler(self, cmd):
367
        """Process a BlobCommand."""
368
        if cmd.mark is not None:
0.64.36 by Ian Clatworthy
fix head tracking when unmarked commits used
369
            dataref = cmd.id
0.64.5 by Ian Clatworthy
first cut at generic processing method
370
        else:
371
            dataref = osutils.sha_strings(cmd.data)
0.64.24 by Ian Clatworthy
smart blob caching using analysis done by --info
372
        self.cache_mgr.store_blob(dataref, cmd.data)
0.64.5 by Ian Clatworthy
first cut at generic processing method
373
374
    def checkpoint_handler(self, cmd):
375
        """Process a CheckpointCommand."""
0.64.27 by Ian Clatworthy
1st cut at performance tuning
376
        # Commit the current write group and start a new one
377
        self.repo.commit_write_group()
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
378
        self._save_id_map()
0.64.27 by Ian Clatworthy
1st cut at performance tuning
379
        self.repo.start_write_group()
0.64.5 by Ian Clatworthy
first cut at generic processing method
380
381
    def commit_handler(self, cmd):
382
        """Process a CommitCommand."""
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
383
        if self.skip_total and self._revision_count < self.skip_total:
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
384
            self.cache_mgr.track_heads(cmd)
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
385
            # Check that we really do know about this commit-id
386
            if not self.cache_mgr.revision_ids.has_key(cmd.id):
387
                raise plugin_errors.BadRestart(cmd.id)
388
            # Consume the file commands and free any non-sticky blobs
389
            for fc in cmd.file_iter():
390
                pass
391
            self.cache_mgr._blobs = {}
392
            self._revision_count += 1
393
            # If we're finished getting back to where we were,
394
            # load the file-ids cache
395
            if self._revision_count == self.skip_total:
396
                self._gen_file_ids_cache()
397
                self.note("Generated the file-ids cache - %d entries",
398
                    len(self.cache_mgr.file_ids.keys()))
399
            return
0.68.7 by Pieter de Bie
Add importing and exporting of marks to bzr-fastimport
400
        if self.first_incremental_commit:
401
            self.first_incremental_commit = None
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
402
            parents = self.cache_mgr.track_heads(cmd)
0.68.7 by Pieter de Bie
Add importing and exporting of marks to bzr-fastimport
403
            self._gen_file_ids_cache(parents)
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
404
405
        # 'Commit' the revision and report progress
0.84.4 by Ian Clatworthy
improved-but-not-yet-working CHKInventory support
406
        handler = self.commit_handler_factory(cmd, self.cache_mgr,
407
            self.rev_store, verbose=self.verbose)
0.64.27 by Ian Clatworthy
1st cut at performance tuning
408
        handler.process()
0.64.36 by Ian Clatworthy
fix head tracking when unmarked commits used
409
        self.cache_mgr.revision_ids[cmd.id] = handler.revision_id
0.64.27 by Ian Clatworthy
1st cut at performance tuning
410
        self._revision_count += 1
0.64.36 by Ian Clatworthy
fix head tracking when unmarked commits used
411
        self.report_progress("(%s)" % cmd.id)
0.64.31 by Ian Clatworthy
fix branch updating for the single branch case
412
413
        # Check if we should finish up or automatically checkpoint
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
414
        if (self.max_commits is not None and
415
            self._revision_count >= self.max_commits):
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
416
            self.note("Stopping after reaching requested count of commits")
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
417
            self.finished = True
418
        elif self._revision_count % self.checkpoint_every == 0:
419
            self.note("%d commits - automatic checkpoint triggered",
420
                self._revision_count)
421
            self.checkpoint_handler(None)
0.64.1 by Ian Clatworthy
1st cut: gfi parser + --info processing method
422
0.64.82 by Ian Clatworthy
Merge Pieter de Bie's export-fixes branch
423
    def _gen_file_ids_cache(self, revs=False):
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
424
        """Generate the file-id cache by searching repository inventories.
425
        """
426
        # Get the interesting revisions - the heads
0.68.7 by Pieter de Bie
Add importing and exporting of marks to bzr-fastimport
427
        if revs:
428
            head_ids = revs
429
        else:
430
            head_ids = self.cache_mgr.heads.keys()
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
431
        revision_ids = [self.cache_mgr.revision_ids[h] for h in head_ids]
432
433
        # Update the fileid cache
434
        file_ids = {}
435
        for revision_id in revision_ids:
436
            inv = self.repo.revision_tree(revision_id).inventory
0.64.93 by Ian Clatworthy
minor comment clean-ups
437
            # Cache the inventories while we're at it
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
438
            self.cache_mgr.inventories[revision_id] = inv
439
            for path, ie in inv.iter_entries():
440
                file_ids[path] = ie.file_id
441
        self.cache_mgr.file_ids = file_ids
442
0.64.25 by Ian Clatworthy
slightly better progress reporting
443
    def report_progress(self, details=''):
444
        # TODO: use a progress bar with ETA enabled
0.64.41 by Ian Clatworthy
update multiple working trees if requested
445
        if self._revision_count % self.progress_every == 0:
0.64.26 by Ian Clatworthy
more progress reporting tweaks
446
            if self.total_commits is not None:
447
                counts = "%d/%d" % (self._revision_count, self.total_commits)
448
                eta = progress.get_eta(self._start_time, self._revision_count,
449
                    self.total_commits)
0.64.33 by Ian Clatworthy
make tree updating optional and minor UI improvements
450
                eta_str = progress.str_tdelta(eta)
451
                if eta_str.endswith('--'):
452
                    eta_str = ''
453
                else:
454
                    eta_str = '[%s] ' % eta_str
0.64.26 by Ian Clatworthy
more progress reporting tweaks
455
            else:
456
                counts = "%d" % (self._revision_count,)
457
                eta_str = ''
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
458
            self.note("%s commits processed %s%s" % (counts, eta_str, details))
0.64.25 by Ian Clatworthy
slightly better progress reporting
459
0.64.1 by Ian Clatworthy
1st cut: gfi parser + --info processing method
460
    def progress_handler(self, cmd):
461
        """Process a ProgressCommand."""
0.64.34 by Ian Clatworthy
report lost branches
462
        # We could use a progress bar here instead
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
463
        self.note("progress %s" % (cmd.message,))
0.64.5 by Ian Clatworthy
first cut at generic processing method
464
465
    def reset_handler(self, cmd):
466
        """Process a ResetCommand."""
0.64.12 by Ian Clatworthy
lightweight tags, filter processor and param validation
467
        if cmd.ref.startswith('refs/tags/'):
0.64.94 by Ian Clatworthy
ignore lightweight tags without a from clause
468
            tag_name = cmd.ref[len('refs/tags/'):]
0.64.95 by Ian Clatworthy
only output warning about missing from clause for lightweight tags in verbose mode
469
            if cmd.from_ is not None:
470
                self._set_tag(tag_name, cmd.from_)
471
            elif self.verbose:
0.64.94 by Ian Clatworthy
ignore lightweight tags without a from clause
472
                self.warning("ignoring reset refs/tags/%s - no from clause"
473
                    % tag_name)
0.64.109 by Ian Clatworthy
initial cut at reset support
474
            return
0.75.1 by Brian de Alwis
Add support for multiple branches by supporting the 'reset' command.
475
476
        if cmd.from_ is not None:
0.64.109 by Ian Clatworthy
initial cut at reset support
477
            self.cache_mgr.track_heads_for_ref(cmd.ref, cmd.from_)
0.64.5 by Ian Clatworthy
first cut at generic processing method
478
479
    def tag_handler(self, cmd):
480
        """Process a TagCommand."""
0.64.107 by Ian Clatworthy
warn on tags with a missing from clause
481
        if cmd.from_ is not None:
482
            self._set_tag(cmd.id, cmd.from_)
483
        else:
484
            self.warning("ignoring tag %s - no from clause" % cmd.id)
0.64.12 by Ian Clatworthy
lightweight tags, filter processor and param validation
485
486
    def _set_tag(self, name, from_):
0.64.93 by Ian Clatworthy
minor comment clean-ups
487
        """Define a tag given a name and import 'from' reference."""
0.64.12 by Ian Clatworthy
lightweight tags, filter processor and param validation
488
        bzr_tag_name = name.decode('utf-8', 'replace')
489
        bzr_rev_id = self.cache_mgr.revision_ids[from_]
0.64.11 by Ian Clatworthy
tag support
490
        self.tags[bzr_tag_name] = bzr_rev_id