1 # (Be in -*- python -*- mode.)
3 # ====================================================================
4 # Copyright (c) 2007-2009 CollabNet. All rights reserved.
6 # This software is licensed as described in the file COPYING, which
7 # you should have received as part of this distribution. The terms
8 # are also available at http://subversion.tigris.org/license-1.html.
9 # If newer versions of this license are posted there, you may use a
10 # newer version instead, at your option.
12 # This software consists of voluntary contributions made by many
13 # individuals. For exact contribution history, see the revision
14 # history and logs, available at http://cvs2svn.tigris.org/.
15 # ====================================================================
17 """Write file contents to a stream of git-fast-import blobs."""
21 from cvs2svn_lib
.symbol
import Trunk
22 from cvs2svn_lib
.cvs_item
import CVSRevisionDelete
23 from cvs2svn_lib
.cvs_item
import CVSSymbol
24 from cvs2svn_lib
.fulltext_revision_recorder
import FulltextRevisionRecorder
25 from cvs2svn_lib
.key_generator
import KeyGenerator
28 class GitRevisionRecorder(FulltextRevisionRecorder
):
29 """Output file revisions to git-fast-import."""
31 def __init__(self
, blob_filename
):
32 self
.blob_filename
= blob_filename
35 self
.dump_file
= open(self
.blob_filename
, 'wb')
36 self
._mark
_generator
= KeyGenerator()
38 def start_file(self
, cvs_file_items
):
39 self
._cvs
_file
_items
= cvs_file_items
41 def _get_original_source(self
, cvs_rev
):
42 """Return the original source of the contents of CVS_REV.
44 Return the first non-delete CVSRevision with the same contents as
45 CVS_REV. 'First' here refers to deltatext order; i.e., the very
46 first revision is HEAD on trunk, then backwards to the root of a
47 branch, then out to the tip of a branch.
49 The candidates are all revisions along the CVS delta-dependency
50 chain until the next one that has a deltatext (inclusive). Of the
51 candidates, CVSRevisionDeletes are disqualified because, even
52 though CVS records their contents, it is impossible to extract
53 their fulltext using commands like 'cvs checkout -p'.
55 If there is no other CVSRevision that has the same content, return
58 # Keep track of the "best" source CVSRevision found so far:
59 best_source_rev
= None
61 for cvs_rev
in itertools
.chain(
62 [cvs_rev
], self
._cvs
_file
_items
.iter_deltatext_ancestors(cvs_rev
)
64 if not isinstance(cvs_rev
, CVSRevisionDelete
):
65 best_source_rev
= cvs_rev
67 if cvs_rev
.deltatext_exists
:
70 return best_source_rev
72 def record_fulltext(self
, cvs_rev
, log
, fulltext
):
73 """Write the fulltext to a blob if it is original and not a delete.
75 The reason we go to this trouble is to avoid writing the same file
76 contents multiple times for a string of revisions that don't have
77 deltatexts (as, for example, happens with dead revisions and
78 imported revisions)."""
80 if isinstance(cvs_rev
, CVSRevisionDelete
):
81 # There is no need to record a delete revision, and its token
82 # will never be needed:
85 source
= self
._get
_original
_source
(cvs_rev
)
87 if source
.id == cvs_rev
.id:
88 # Revision is its own source; write it out:
89 mark
= self
._mark
_generator
.gen_id()
90 self
.dump_file
.write('blob\n')
91 self
.dump_file
.write('mark :%d\n' % (mark
,))
92 self
.dump_file
.write('data %d\n' % (len(fulltext
),))
93 self
.dump_file
.write(fulltext
)
94 self
.dump_file
.write('\n')
97 # Return as revision_recorder_token the CVSRevision.id of the
98 # original source revision:
99 return source
.revision_recorder_token
101 def finish_file(self
, cvs_file_items
):
102 # Determine the original source of each CVSSymbol, and store it as
103 # the symbol's revision_recorder_token.
104 for cvs_item
in cvs_file_items
.values():
105 if isinstance(cvs_item
, CVSSymbol
):
106 cvs_source
= cvs_item
.get_cvs_revision_source(cvs_file_items
)
107 cvs_item
.revision_recorder_token
= cvs_source
.revision_recorder_token
109 del self
._cvs
_file
_items
112 self
.dump_file
.close()