~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commit.py

  • Committer: Martin Pool
  • Date: 2005-05-12 02:18:48 UTC
  • Revision ID: mbp@sourcefrog.net-20050512021848-d1a727373aee2c85
- WorkingTree loads statcache in constructor and holds
  it permanently

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
 
18
18
 
19
 
def commit(branch, message,
20
 
           timestamp=None,
21
 
           timezone=None,
 
19
def commit(branch, message, timestamp=None, timezone=None,
22
20
           committer=None,
23
 
           verbose=True,
24
 
           specific_files=None,
25
 
           rev_id=None):
 
21
           verbose=False):
26
22
    """Commit working copy as a new revision.
27
23
 
28
24
    The basic approach is to add all the file texts into the
41
37
 
42
38
    timestamp -- if not None, seconds-since-epoch for a
43
39
         postdated/predated commit.
44
 
 
45
 
    specific_files
46
 
        If true, commit only those files.
47
 
 
48
 
    rev_id
49
 
        If set, use this as the new revision id.
50
 
        Useful for test or import commands that need to tightly
51
 
        control what revisions are assigned.  If you duplicate
52
 
        a revision id that exists elsewhere it is your own fault.
53
 
        If null (default), a time/random revision id is generated.
54
40
    """
55
41
 
56
42
    import os, time, tempfile
57
43
 
58
44
    from inventory import Inventory
59
45
    from osutils import isdir, isfile, sha_string, quotefn, \
60
 
         local_time_offset, username, kind_marker, is_inside_any
 
46
         local_time_offset, username
61
47
    
62
48
    from branch import gen_file_id
63
49
    from errors import BzrError
64
50
    from revision import Revision
 
51
    from textui import show_status
65
52
    from trace import mutter, note
66
53
 
67
54
    branch._need_writelock()
68
55
 
 
56
    ## TODO: Show branch names
 
57
 
 
58
    # TODO: Don't commit if there are no changes, unless forced?
 
59
 
69
60
    # First walk over the working inventory; and both update that
70
61
    # and also build a new revision inventory.  The revision
71
62
    # inventory needs to hold the text-id, sha1 and size of the
74
65
    # detect missing/deleted files, and remove them from the
75
66
    # working inventory.
76
67
 
77
 
    work_tree = branch.working_tree()
78
 
    work_inv = work_tree.inventory
 
68
    work_inv = branch.read_working_inventory()
79
69
    inv = Inventory()
80
70
    basis = branch.basis_tree()
81
71
    basis_inv = basis.inventory
82
72
    missing_ids = []
83
 
 
84
 
    if verbose:
85
 
        note('looking for changes...')
86
 
        
87
73
    for path, entry in work_inv.iter_entries():
 
74
        ## TODO: Cope with files that have gone missing.
 
75
 
88
76
        ## TODO: Check that the file kind has not changed from the previous
89
77
        ## revision of this file (if any).
90
78
 
94
82
        file_id = entry.file_id
95
83
        mutter('commit prep file %s, id %r ' % (p, file_id))
96
84
 
97
 
        if specific_files and not is_inside_any(specific_files, path):
98
 
            if basis_inv.has_id(file_id):
99
 
                # carry over with previous state
100
 
                inv.add(basis_inv[file_id].copy())
101
 
            else:
102
 
                # omit this from committed inventory
103
 
                pass
104
 
            continue
105
 
 
106
 
        if not work_tree.has_id(file_id):
 
85
        if not os.path.exists(p):
 
86
            mutter("    file is missing, removing from inventory")
107
87
            if verbose:
108
 
                print('deleted %s%s' % (path, kind_marker(entry.kind)))
109
 
            mutter("    file is missing, removing from inventory")
 
88
                show_status('D', entry.kind, quotefn(path))
110
89
            missing_ids.append(file_id)
111
90
            continue
112
91
 
 
92
        # TODO: Handle files that have been deleted
 
93
 
 
94
        # TODO: Maybe a special case for empty files?  Seems a
 
95
        # waste to store them many times.
 
96
 
113
97
        inv.add(entry)
114
98
 
115
99
        if basis_inv.has_id(file_id):
120
104
 
121
105
        if entry.kind == 'directory':
122
106
            if not isdir(p):
123
 
                raise BzrError("%s is entered as directory but not a directory"
124
 
                               % quotefn(p))
 
107
                raise BzrError("%s is entered as directory but not a directory" % quotefn(p))
125
108
        elif entry.kind == 'file':
126
109
            if not isfile(p):
127
110
                raise BzrError("%s is entered as file but is not a file" % quotefn(p))
128
111
 
129
 
            new_sha1 = work_tree.get_file_sha1(file_id)
 
112
            content = file(p, 'rb').read()
 
113
 
 
114
            entry.text_sha1 = sha_string(content)
 
115
            entry.text_size = len(content)
130
116
 
131
117
            old_ie = basis_inv.has_id(file_id) and basis_inv[file_id]
132
118
            if (old_ie
133
 
                and old_ie.text_sha1 == new_sha1):
 
119
                and (old_ie.text_size == entry.text_size)
 
120
                and (old_ie.text_sha1 == entry.text_sha1)):
134
121
                ## assert content == basis.get_file(file_id).read()
135
 
                entry.text_id = old_ie.text_id
136
 
                entry.text_sha1 = new_sha1
137
 
                entry.text_size = old_ie.text_size
 
122
                entry.text_id = basis_inv[file_id].text_id
138
123
                mutter('    unchanged from previous text_id {%s}' %
139
124
                       entry.text_id)
 
125
 
140
126
            else:
141
 
                content = file(p, 'rb').read()
142
 
 
143
 
                # calculate the sha again, just in case the file contents
144
 
                # changed since we updated the cache
145
 
                entry.text_sha1 = sha_string(content)
146
 
                entry.text_size = len(content)
147
 
 
148
127
                entry.text_id = gen_file_id(entry.name)
149
128
                branch.text_store.add(content, entry.text_id)
150
129
                mutter('    stored with text_id {%s}' % entry.text_id)
151
130
                if verbose:
152
131
                    if not old_ie:
153
 
                        print('added %s' % path)
 
132
                        state = 'A'
154
133
                    elif (old_ie.name == entry.name
155
134
                          and old_ie.parent_id == entry.parent_id):
156
 
                        print('modified %s' % path)
 
135
                        state = 'M'
157
136
                    else:
158
 
                        print('renamed %s' % path)
 
137
                        state = 'R'
159
138
 
 
139
                    show_status(state, entry.kind, quotefn(path))
160
140
 
161
141
    for file_id in missing_ids:
162
 
        # Any files that have been deleted are now removed from the
163
 
        # working inventory.  Files that were not selected for commit
164
 
        # are left as they were in the working inventory and ommitted
165
 
        # from the revision inventory.
166
 
        
167
142
        # have to do this later so we don't mess up the iterator.
168
143
        # since parents may be removed before their children we
169
144
        # have to test.
174
149
            del work_inv[file_id]
175
150
 
176
151
 
177
 
    if rev_id is None:
178
 
        rev_id = _gen_revision_id(time.time())
179
 
    inv_id = rev_id
 
152
    inv_id = rev_id = _gen_revision_id(time.time())
180
153
 
181
154
    inv_tmp = tempfile.TemporaryFile()
182
155
    inv.write_xml(inv_tmp)
220
193
    ## TODO: Also calculate and store the inventory SHA1
221
194
    mutter("committing patch r%d" % (branch.revno() + 1))
222
195
 
 
196
 
223
197
    branch.append_revision(rev_id)
224
198
 
225
199
    if verbose: