/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.64.41 by Ian Clatworthy
update multiple working trees if requested
170
        # Decide how often to automatically report progress
171
        # (not a parameter yet)
172
        self.progress_every = _DEFAULT_AUTO_PROGRESS
173
        if self.verbose:
174
            self.progress_every = self.progress_every / 10
175
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
176
        # Decide how often to automatically checkpoint
177
        self.checkpoint_every = int(self.params.get('checkpoint',
178
            _DEFAULT_AUTO_CHECKPOINT))
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
179
0.64.44 by Ian Clatworthy
smart caching of serialised inventories
180
        # Decide how big to make the inventory cache
181
        self.inventory_cache_size = int(self.params.get('inv-cache',
182
            _DEFAULT_INV_CACHE_SIZE))
183
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
184
        # Find the maximum number of commits to import (None means all)
185
        # and prepare progress reporting. Just in case the info file
186
        # has an outdated count of commits, we store the max counts
187
        # at which we need to terminate separately to the total used
188
        # for progress tracking.
189
        try:
190
            self.max_commits = int(self.params['count'])
0.64.38 by Ian Clatworthy
clean-up doc ready for initial release
191
            if self.max_commits < 0:
192
                self.max_commits = None
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
193
        except KeyError:
194
            self.max_commits = None
0.64.25 by Ian Clatworthy
slightly better progress reporting
195
        if self.info is not None:
196
            self.total_commits = int(self.info['Command counts']['commit'])
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
197
            if (self.max_commits is not None and
198
                self.total_commits > self.max_commits):
199
                self.total_commits = self.max_commits
0.64.25 by Ian Clatworthy
slightly better progress reporting
200
        else:
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
201
            self.total_commits = self.max_commits
0.64.25 by Ian Clatworthy
slightly better progress reporting
202
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
203
    def _revision_store_factory(self):
204
        """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
205
        new_repo_api = hasattr(self.repo, 'revisions')
206
        if new_repo_api:
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
207
            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
208
        elif not self._experimental:
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
209
            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
210
        else:
211
            def fulltext_when(count):
212
                total = self.total_commits
213
                if total is not None and count == total:
214
                    fulltext = True
215
                else:
216
                    # Create an inventory fulltext every 200 revisions
217
                    fulltext = count % 200 == 0
218
                if fulltext:
219
                    self.note("%d commits - storing inventory as full-text",
220
                        count)
221
                return fulltext
222
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
223
            return revision_store.ImportRevisionStore1(
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
224
                self.repo, self.inventory_cache_size,
225
                fulltext_when=fulltext_when)
226
0.64.27 by Ian Clatworthy
1st cut at performance tuning
227
    def _process(self, command_iter):
228
        # if anything goes wrong, abort the write group if any
229
        try:
230
            processor.ImportProcessor._process(self, command_iter)
231
        except:
232
            if self.repo is not None and self.repo.is_in_write_group():
233
                self.repo.abort_write_group()
234
            raise
235
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
236
    def post_process(self):
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
237
        # Commit the current write group and checkpoint the id map
0.64.27 by Ian Clatworthy
1st cut at performance tuning
238
        self.repo.commit_write_group()
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
239
        self._save_id_map()
0.64.27 by Ian Clatworthy
1st cut at performance tuning
240
0.64.82 by Ian Clatworthy
Merge Pieter de Bie's export-fixes branch
241
        if self.params.get("export-marks") is not None:
0.78.5 by Ian Clatworthy
move import/export of marks into a module
242
            marks_file.export_marks(self.params.get("export-marks"),
243
                self.cache_mgr.revision_ids)
0.68.7 by Pieter de Bie
Add importing and exporting of marks to bzr-fastimport
244
0.64.31 by Ian Clatworthy
fix branch updating for the single branch case
245
        # Update the branches
246
        self.note("Updating branch information ...")
0.78.4 by Ian Clatworthy
move GenericBranchUpdater into its own module
247
        updater = branch_updater.BranchUpdater(self.repo, self.branch,
248
            self.cache_mgr, helpers.invert_dictset(self.cache_mgr.heads),
0.64.64 by Ian Clatworthy
save tags known about in each branch
249
            self.cache_mgr.last_ref, self.tags)
0.64.34 by Ian Clatworthy
report lost branches
250
        branches_updated, branches_lost = updater.update()
251
        self._branch_count = len(branches_updated)
252
253
        # Tell the user about branches that were not created
254
        if branches_lost:
0.64.37 by Ian Clatworthy
create branches as required
255
            if not self.repo.is_shared():
256
                self.warning("Cannot import multiple branches into "
257
                    "an unshared repository")
258
            self.warning("Not creating branches for these head revisions:")
0.64.34 by Ian Clatworthy
report lost branches
259
            for lost_info in branches_lost:
260
                head_revision = lost_info[1]
261
                branch_name = lost_info[0]
0.64.67 by James Westby
Add support for -Dfast-import.
262
                self.note("\t %s = %s", head_revision, branch_name)
0.64.34 by Ian Clatworthy
report lost branches
263
264
        # Update the working trees as requested and dump stats
0.64.33 by Ian Clatworthy
make tree updating optional and minor UI improvements
265
        self._tree_count = 0
0.64.34 by Ian Clatworthy
report lost branches
266
        remind_about_update = True
0.64.54 by Ian Clatworthy
handle existing branches and only count the branches really updated
267
        if self._branch_count == 0:
268
            self.note("no branches to update")
269
            self.note("no working trees to update")
270
            remind_about_update = False
271
        elif self.params.get('trees', False):
0.64.41 by Ian Clatworthy
update multiple working trees if requested
272
            trees = self._get_working_trees(branches_updated)
273
            if trees:
274
                self.note("Updating the working trees ...")
0.64.33 by Ian Clatworthy
make tree updating optional and minor UI improvements
275
                if self.verbose:
276
                    report = delta._ChangeReporter()
277
                else:
278
                    reporter = None
0.64.41 by Ian Clatworthy
update multiple working trees if requested
279
                for wt in trees:
280
                    wt.update(reporter)
281
                    self._tree_count += 1
0.64.34 by Ian Clatworthy
report lost branches
282
                remind_about_update = False
0.64.41 by Ian Clatworthy
update multiple working trees if requested
283
            else:
284
                self.warning("No working trees available to update")
0.64.31 by Ian Clatworthy
fix branch updating for the single branch case
285
        self.dump_stats()
0.64.51 by Ian Clatworthy
disable autopacking
286
287
        # Finish up by telling the user what to do next.
288
        if self._original_max_pack_count:
289
            # We earlier disabled autopacking, creating one pack every
0.64.75 by Ian Clatworthy
if checkpointed, pack repository and delete obsolete_packs
290
            # checkpoint instead. We now pack the repository to optimise
291
            # how data is stored.
292
            if self._revision_count > self.checkpoint_every:
293
                self.note("Packing repository ...")
294
                self.repo.pack()
295
                # To be conservative, packing puts the old packs and
296
                # indices in obsolete_packs. We err on the side of
297
                # optimism and clear out that directory to save space.
298
                self.note("Removing obsolete packs ...")
299
                # TODO: Use a public API for this once one exists
300
                repo_transport = self.repo._pack_collection.transport
301
                repo_transport.clone('obsolete_packs').delete_multi(
302
                    repo_transport.list_dir('obsolete_packs'))
0.64.34 by Ian Clatworthy
report lost branches
303
        if remind_about_update:
0.64.75 by Ian Clatworthy
if checkpointed, pack repository and delete obsolete_packs
304
            # This message is explicitly not timestamped.
0.64.51 by Ian Clatworthy
disable autopacking
305
            note("To refresh the working tree for a branch, "
306
                "use 'bzr update'.")
0.64.41 by Ian Clatworthy
update multiple working trees if requested
307
308
    def _get_working_trees(self, branches):
309
        """Get the working trees for branches in the repository."""
310
        result = []
311
        wt_expected = self.repo.make_working_trees()
312
        for br in branches:
313
            if br == self.branch and br is not None:
314
                wt = self.working_tree
315
            elif wt_expected:
316
                try:
317
                    wt = br.bzrdir.open_workingtree()
318
                except errors.NoWorkingTree:
319
                    self.warning("No working tree for branch %s", br)
320
                    continue
321
            else:
322
                continue
323
            result.append(wt)
324
        return result
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
325
326
    def dump_stats(self):
0.64.33 by Ian Clatworthy
make tree updating optional and minor UI improvements
327
        time_required = progress.str_tdelta(time.time() - self._start_time)
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
328
        rc = self._revision_count - self.skip_total
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
329
        bc = self._branch_count
0.64.33 by Ian Clatworthy
make tree updating optional and minor UI improvements
330
        wtc = self._tree_count
331
        self.note("Imported %d %s, updating %d %s and %d %s in %s",
0.64.32 by Ian Clatworthy
move single_plural into helpers
332
            rc, helpers.single_plural(rc, "revision", "revisions"),
333
            bc, helpers.single_plural(bc, "branch", "branches"),
0.64.33 by Ian Clatworthy
make tree updating optional and minor UI improvements
334
            wtc, helpers.single_plural(wtc, "tree", "trees"),
335
            time_required)
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
336
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
337
    def _init_id_map(self):
338
        """Load the id-map and check it matches the repository.
339
        
340
        :return: the number of entries in the map
341
        """
342
        # Currently, we just check the size. In the future, we might
343
        # decide to be more paranoid and check that the revision-ids
344
        # are identical as well.
345
        self.cache_mgr.revision_ids, known = idmapfile.load_id_map(
346
            self.id_map_path)
347
        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
348
        if existing_count < known:
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
349
            raise plugin_errors.BadRepositorySize(known, existing_count)
350
        return known
351
352
    def _save_id_map(self):
353
        """Save the id-map."""
354
        # Save the whole lot every time. If this proves a problem, we can
355
        # change to 'append just the new ones' at a later time.
356
        idmapfile.save_id_map(self.id_map_path, self.cache_mgr.revision_ids)
357
0.64.5 by Ian Clatworthy
first cut at generic processing method
358
    def blob_handler(self, cmd):
359
        """Process a BlobCommand."""
360
        if cmd.mark is not None:
0.64.36 by Ian Clatworthy
fix head tracking when unmarked commits used
361
            dataref = cmd.id
0.64.5 by Ian Clatworthy
first cut at generic processing method
362
        else:
363
            dataref = osutils.sha_strings(cmd.data)
0.64.24 by Ian Clatworthy
smart blob caching using analysis done by --info
364
        self.cache_mgr.store_blob(dataref, cmd.data)
0.64.5 by Ian Clatworthy
first cut at generic processing method
365
366
    def checkpoint_handler(self, cmd):
367
        """Process a CheckpointCommand."""
0.64.27 by Ian Clatworthy
1st cut at performance tuning
368
        # Commit the current write group and start a new one
369
        self.repo.commit_write_group()
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
370
        self._save_id_map()
0.64.27 by Ian Clatworthy
1st cut at performance tuning
371
        self.repo.start_write_group()
0.64.5 by Ian Clatworthy
first cut at generic processing method
372
373
    def commit_handler(self, cmd):
374
        """Process a CommitCommand."""
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
375
        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
376
            self.cache_mgr.track_heads(cmd)
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
377
            # Check that we really do know about this commit-id
378
            if not self.cache_mgr.revision_ids.has_key(cmd.id):
379
                raise plugin_errors.BadRestart(cmd.id)
380
            # Consume the file commands and free any non-sticky blobs
381
            for fc in cmd.file_iter():
382
                pass
383
            self.cache_mgr._blobs = {}
384
            self._revision_count += 1
385
            # If we're finished getting back to where we were,
386
            # load the file-ids cache
387
            if self._revision_count == self.skip_total:
388
                self._gen_file_ids_cache()
389
                self.note("Generated the file-ids cache - %d entries",
390
                    len(self.cache_mgr.file_ids.keys()))
391
            return
0.68.7 by Pieter de Bie
Add importing and exporting of marks to bzr-fastimport
392
        if self.first_incremental_commit:
393
            self.first_incremental_commit = None
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
394
            parents = self.cache_mgr.track_heads(cmd)
0.68.7 by Pieter de Bie
Add importing and exporting of marks to bzr-fastimport
395
            self._gen_file_ids_cache(parents)
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
396
397
        # 'Commit' the revision and report progress
0.81.3 by Ian Clatworthy
enhance RevisionLoader to try inventory deltas & decide on rich-roots
398
        handler = bzr_commit_handler.InventoryCommitHandler(cmd,
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
399
            self.cache_mgr, self.rev_store, verbose=self.verbose)
0.64.27 by Ian Clatworthy
1st cut at performance tuning
400
        handler.process()
0.64.36 by Ian Clatworthy
fix head tracking when unmarked commits used
401
        self.cache_mgr.revision_ids[cmd.id] = handler.revision_id
0.64.27 by Ian Clatworthy
1st cut at performance tuning
402
        self._revision_count += 1
0.64.36 by Ian Clatworthy
fix head tracking when unmarked commits used
403
        self.report_progress("(%s)" % cmd.id)
0.64.31 by Ian Clatworthy
fix branch updating for the single branch case
404
405
        # Check if we should finish up or automatically checkpoint
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
406
        if (self.max_commits is not None and
407
            self._revision_count >= self.max_commits):
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
408
            self.note("Stopping after reaching requested count of commits")
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
409
            self.finished = True
410
        elif self._revision_count % self.checkpoint_every == 0:
411
            self.note("%d commits - automatic checkpoint triggered",
412
                self._revision_count)
413
            self.checkpoint_handler(None)
0.64.1 by Ian Clatworthy
1st cut: gfi parser + --info processing method
414
0.64.82 by Ian Clatworthy
Merge Pieter de Bie's export-fixes branch
415
    def _gen_file_ids_cache(self, revs=False):
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
416
        """Generate the file-id cache by searching repository inventories.
417
        """
418
        # Get the interesting revisions - the heads
0.68.7 by Pieter de Bie
Add importing and exporting of marks to bzr-fastimport
419
        if revs:
420
            head_ids = revs
421
        else:
422
            head_ids = self.cache_mgr.heads.keys()
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
423
        revision_ids = [self.cache_mgr.revision_ids[h] for h in head_ids]
424
425
        # Update the fileid cache
426
        file_ids = {}
427
        for revision_id in revision_ids:
428
            inv = self.repo.revision_tree(revision_id).inventory
0.64.93 by Ian Clatworthy
minor comment clean-ups
429
            # Cache the inventories while we're at it
0.64.50 by Ian Clatworthy
cleanly restart after an interruption - basic mirroring
430
            self.cache_mgr.inventories[revision_id] = inv
431
            for path, ie in inv.iter_entries():
432
                file_ids[path] = ie.file_id
433
        self.cache_mgr.file_ids = file_ids
434
0.64.25 by Ian Clatworthy
slightly better progress reporting
435
    def report_progress(self, details=''):
436
        # TODO: use a progress bar with ETA enabled
0.64.41 by Ian Clatworthy
update multiple working trees if requested
437
        if self._revision_count % self.progress_every == 0:
0.64.26 by Ian Clatworthy
more progress reporting tweaks
438
            if self.total_commits is not None:
439
                counts = "%d/%d" % (self._revision_count, self.total_commits)
440
                eta = progress.get_eta(self._start_time, self._revision_count,
441
                    self.total_commits)
0.64.33 by Ian Clatworthy
make tree updating optional and minor UI improvements
442
                eta_str = progress.str_tdelta(eta)
443
                if eta_str.endswith('--'):
444
                    eta_str = ''
445
                else:
446
                    eta_str = '[%s] ' % eta_str
0.64.26 by Ian Clatworthy
more progress reporting tweaks
447
            else:
448
                counts = "%d" % (self._revision_count,)
449
                eta_str = ''
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
450
            self.note("%s commits processed %s%s" % (counts, eta_str, details))
0.64.25 by Ian Clatworthy
slightly better progress reporting
451
0.64.1 by Ian Clatworthy
1st cut: gfi parser + --info processing method
452
    def progress_handler(self, cmd):
453
        """Process a ProgressCommand."""
0.64.34 by Ian Clatworthy
report lost branches
454
        # We could use a progress bar here instead
0.64.28 by Ian Clatworthy
checkpoint and count params to generic processor
455
        self.note("progress %s" % (cmd.message,))
0.64.5 by Ian Clatworthy
first cut at generic processing method
456
457
    def reset_handler(self, cmd):
458
        """Process a ResetCommand."""
0.64.12 by Ian Clatworthy
lightweight tags, filter processor and param validation
459
        if cmd.ref.startswith('refs/tags/'):
0.64.94 by Ian Clatworthy
ignore lightweight tags without a from clause
460
            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
461
            if cmd.from_ is not None:
462
                self._set_tag(tag_name, cmd.from_)
463
            elif self.verbose:
0.64.94 by Ian Clatworthy
ignore lightweight tags without a from clause
464
                self.warning("ignoring reset refs/tags/%s - no from clause"
465
                    % tag_name)
0.64.109 by Ian Clatworthy
initial cut at reset support
466
            return
0.75.1 by Brian de Alwis
Add support for multiple branches by supporting the 'reset' command.
467
0.75.2 by Brian de Alwis
Reset takes a <commitsh> and not just a revid; added note to
468
	# FIXME: cmd.from_ is a committish and thus could reference
0.64.109 by Ian Clatworthy
initial cut at reset support
469
	# another branch.  Create a method for resolving commitish's.
0.75.1 by Brian de Alwis
Add support for multiple branches by supporting the 'reset' command.
470
        if cmd.from_ is not None:
0.64.109 by Ian Clatworthy
initial cut at reset support
471
            self.cache_mgr.track_heads_for_ref(cmd.ref, cmd.from_)
0.64.5 by Ian Clatworthy
first cut at generic processing method
472
473
    def tag_handler(self, cmd):
474
        """Process a TagCommand."""
0.64.107 by Ian Clatworthy
warn on tags with a missing from clause
475
        if cmd.from_ is not None:
476
            self._set_tag(cmd.id, cmd.from_)
477
        else:
478
            self.warning("ignoring tag %s - no from clause" % cmd.id)
0.64.12 by Ian Clatworthy
lightweight tags, filter processor and param validation
479
480
    def _set_tag(self, name, from_):
0.64.93 by Ian Clatworthy
minor comment clean-ups
481
        """Define a tag given a name and import 'from' reference."""
0.64.12 by Ian Clatworthy
lightweight tags, filter processor and param validation
482
        bzr_tag_name = name.decode('utf-8', 'replace')
483
        bzr_rev_id = self.cache_mgr.revision_ids[from_]
0.64.11 by Ian Clatworthy
tag support
484
        self.tags[bzr_tag_name] = bzr_rev_id