~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commit.py

  • Committer: Martin Pool
  • Date: 2005-05-30 01:37:52 UTC
  • Revision ID: mbp@sourcefrog.net-20050530013751-650874ded00ae1a1
- Use explicit lock methods on a branch, rather than doing it
  implicitly from the Branch constructor and relying on destroying the
  branch to release the lock.

- New with_readlock, _with_writelock decorators for branch methods.

- Branch locks can now be taken several times by a single caller, but
  they forbid upgrading or downgrading.

- Don't need assertions about whether the branch is locked anymore.

Show diffs side-by-side

added added

removed removed

Lines of Context:
64
64
    from revision import Revision
65
65
    from trace import mutter, note
66
66
 
67
 
    branch._need_writelock()
68
 
 
69
 
    # First walk over the working inventory; and both update that
70
 
    # and also build a new revision inventory.  The revision
71
 
    # inventory needs to hold the text-id, sha1 and size of the
72
 
    # actual file versions committed in the revision.  (These are
73
 
    # not present in the working inventory.)  We also need to
74
 
    # detect missing/deleted files, and remove them from the
75
 
    # working inventory.
76
 
 
77
 
    work_tree = branch.working_tree()
78
 
    work_inv = work_tree.inventory
79
 
    inv = Inventory()
80
 
    basis = branch.basis_tree()
81
 
    basis_inv = basis.inventory
82
 
    missing_ids = []
83
 
 
84
 
    if verbose:
85
 
        note('looking for changes...')
86
 
        
87
 
    for path, entry in work_inv.iter_entries():
88
 
        ## TODO: Check that the file kind has not changed from the previous
89
 
        ## revision of this file (if any).
90
 
 
91
 
        entry = entry.copy()
92
 
 
93
 
        p = branch.abspath(path)
94
 
        file_id = entry.file_id
95
 
        mutter('commit prep file %s, id %r ' % (p, file_id))
96
 
 
97
 
        if specific_files and not is_inside_any(specific_files, path):
 
67
    branch.lock('w')
 
68
 
 
69
    try:
 
70
        # First walk over the working inventory; and both update that
 
71
        # and also build a new revision inventory.  The revision
 
72
        # inventory needs to hold the text-id, sha1 and size of the
 
73
        # actual file versions committed in the revision.  (These are
 
74
        # not present in the working inventory.)  We also need to
 
75
        # detect missing/deleted files, and remove them from the
 
76
        # working inventory.
 
77
 
 
78
        work_tree = branch.working_tree()
 
79
        work_inv = work_tree.inventory
 
80
        inv = Inventory()
 
81
        basis = branch.basis_tree()
 
82
        basis_inv = basis.inventory
 
83
        missing_ids = []
 
84
 
 
85
        if verbose:
 
86
            note('looking for changes...')
 
87
 
 
88
        for path, entry in work_inv.iter_entries():
 
89
            ## TODO: Check that the file kind has not changed from the previous
 
90
            ## revision of this file (if any).
 
91
 
 
92
            entry = entry.copy()
 
93
 
 
94
            p = branch.abspath(path)
 
95
            file_id = entry.file_id
 
96
            mutter('commit prep file %s, id %r ' % (p, file_id))
 
97
 
 
98
            if specific_files and not is_inside_any(specific_files, path):
 
99
                if basis_inv.has_id(file_id):
 
100
                    # carry over with previous state
 
101
                    inv.add(basis_inv[file_id].copy())
 
102
                else:
 
103
                    # omit this from committed inventory
 
104
                    pass
 
105
                continue
 
106
 
 
107
            if not work_tree.has_id(file_id):
 
108
                if verbose:
 
109
                    print('deleted %s%s' % (path, kind_marker(entry.kind)))
 
110
                mutter("    file is missing, removing from inventory")
 
111
                missing_ids.append(file_id)
 
112
                continue
 
113
 
 
114
            inv.add(entry)
 
115
 
98
116
            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):
107
 
            if verbose:
108
 
                print('deleted %s%s' % (path, kind_marker(entry.kind)))
109
 
            mutter("    file is missing, removing from inventory")
110
 
            missing_ids.append(file_id)
111
 
            continue
112
 
 
113
 
        inv.add(entry)
114
 
 
115
 
        if basis_inv.has_id(file_id):
116
 
            old_kind = basis_inv[file_id].kind
117
 
            if old_kind != entry.kind:
118
 
                raise BzrError("entry %r changed kind from %r to %r"
119
 
                        % (file_id, old_kind, entry.kind))
120
 
 
121
 
        if entry.kind == 'directory':
122
 
            if not isdir(p):
123
 
                raise BzrError("%s is entered as directory but not a directory"
124
 
                               % quotefn(p))
125
 
        elif entry.kind == 'file':
126
 
            if not isfile(p):
127
 
                raise BzrError("%s is entered as file but is not a file" % quotefn(p))
128
 
 
129
 
            new_sha1 = work_tree.get_file_sha1(file_id)
130
 
 
131
 
            old_ie = basis_inv.has_id(file_id) and basis_inv[file_id]
132
 
            if (old_ie
133
 
                and old_ie.text_sha1 == new_sha1):
134
 
                ## 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
138
 
                mutter('    unchanged from previous text_id {%s}' %
139
 
                       entry.text_id)
140
 
            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
 
                entry.text_id = gen_file_id(entry.name)
149
 
                branch.text_store.add(content, entry.text_id)
150
 
                mutter('    stored with text_id {%s}' % entry.text_id)
151
 
                if verbose:
152
 
                    if not old_ie:
153
 
                        print('added %s' % path)
154
 
                    elif (old_ie.name == entry.name
155
 
                          and old_ie.parent_id == entry.parent_id):
156
 
                        print('modified %s' % path)
157
 
                    else:
158
 
                        print('renamed %s' % path)
159
 
 
160
 
 
161
 
    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
 
        # have to do this later so we don't mess up the iterator.
168
 
        # since parents may be removed before their children we
169
 
        # have to test.
170
 
 
171
 
        # FIXME: There's probably a better way to do this; perhaps
172
 
        # the workingtree should know how to filter itbranch.
173
 
        if work_inv.has_id(file_id):
174
 
            del work_inv[file_id]
175
 
 
176
 
 
177
 
    if rev_id is None:
178
 
        rev_id = _gen_revision_id(time.time())
179
 
    inv_id = rev_id
180
 
 
181
 
    inv_tmp = tempfile.TemporaryFile()
182
 
    inv.write_xml(inv_tmp)
183
 
    inv_tmp.seek(0)
184
 
    branch.inventory_store.add(inv_tmp, inv_id)
185
 
    mutter('new inventory_id is {%s}' % inv_id)
186
 
 
187
 
    branch._write_inventory(work_inv)
188
 
 
189
 
    if timestamp == None:
190
 
        timestamp = time.time()
191
 
 
192
 
    if committer == None:
193
 
        committer = username()
194
 
 
195
 
    if timezone == None:
196
 
        timezone = local_time_offset()
197
 
 
198
 
    mutter("building commit log message")
199
 
    rev = Revision(timestamp=timestamp,
200
 
                   timezone=timezone,
201
 
                   committer=committer,
202
 
                   precursor = branch.last_patch(),
203
 
                   message = message,
204
 
                   inventory_id=inv_id,
205
 
                   revision_id=rev_id)
206
 
 
207
 
    rev_tmp = tempfile.TemporaryFile()
208
 
    rev.write_xml(rev_tmp)
209
 
    rev_tmp.seek(0)
210
 
    branch.revision_store.add(rev_tmp, rev_id)
211
 
    mutter("new revision_id is {%s}" % rev_id)
212
 
 
213
 
    ## XXX: Everything up to here can simply be orphaned if we abort
214
 
    ## the commit; it will leave junk files behind but that doesn't
215
 
    ## matter.
216
 
 
217
 
    ## TODO: Read back the just-generated changeset, and make sure it
218
 
    ## applies and recreates the right state.
219
 
 
220
 
    ## TODO: Also calculate and store the inventory SHA1
221
 
    mutter("committing patch r%d" % (branch.revno() + 1))
222
 
 
223
 
    branch.append_revision(rev_id)
224
 
 
225
 
    if verbose:
226
 
        note("commited r%d" % branch.revno())
 
117
                old_kind = basis_inv[file_id].kind
 
118
                if old_kind != entry.kind:
 
119
                    raise BzrError("entry %r changed kind from %r to %r"
 
120
                            % (file_id, old_kind, entry.kind))
 
121
 
 
122
            if entry.kind == 'directory':
 
123
                if not isdir(p):
 
124
                    raise BzrError("%s is entered as directory but not a directory"
 
125
                                   % quotefn(p))
 
126
            elif entry.kind == 'file':
 
127
                if not isfile(p):
 
128
                    raise BzrError("%s is entered as file but is not a file" % quotefn(p))
 
129
 
 
130
                new_sha1 = work_tree.get_file_sha1(file_id)
 
131
 
 
132
                old_ie = basis_inv.has_id(file_id) and basis_inv[file_id]
 
133
                if (old_ie
 
134
                    and old_ie.text_sha1 == new_sha1):
 
135
                    ## assert content == basis.get_file(file_id).read()
 
136
                    entry.text_id = old_ie.text_id
 
137
                    entry.text_sha1 = new_sha1
 
138
                    entry.text_size = old_ie.text_size
 
139
                    mutter('    unchanged from previous text_id {%s}' %
 
140
                           entry.text_id)
 
141
                else:
 
142
                    content = file(p, 'rb').read()
 
143
 
 
144
                    # calculate the sha again, just in case the file contents
 
145
                    # changed since we updated the cache
 
146
                    entry.text_sha1 = sha_string(content)
 
147
                    entry.text_size = len(content)
 
148
 
 
149
                    entry.text_id = gen_file_id(entry.name)
 
150
                    branch.text_store.add(content, entry.text_id)
 
151
                    mutter('    stored with text_id {%s}' % entry.text_id)
 
152
                    if verbose:
 
153
                        if not old_ie:
 
154
                            print('added %s' % path)
 
155
                        elif (old_ie.name == entry.name
 
156
                              and old_ie.parent_id == entry.parent_id):
 
157
                            print('modified %s' % path)
 
158
                        else:
 
159
                            print('renamed %s' % path)
 
160
 
 
161
 
 
162
        for file_id in missing_ids:
 
163
            # Any files that have been deleted are now removed from the
 
164
            # working inventory.  Files that were not selected for commit
 
165
            # are left as they were in the working inventory and ommitted
 
166
            # from the revision inventory.
 
167
 
 
168
            # have to do this later so we don't mess up the iterator.
 
169
            # since parents may be removed before their children we
 
170
            # have to test.
 
171
 
 
172
            # FIXME: There's probably a better way to do this; perhaps
 
173
            # the workingtree should know how to filter itbranch.
 
174
            if work_inv.has_id(file_id):
 
175
                del work_inv[file_id]
 
176
 
 
177
 
 
178
        if rev_id is None:
 
179
            rev_id = _gen_revision_id(time.time())
 
180
        inv_id = rev_id
 
181
 
 
182
        inv_tmp = tempfile.TemporaryFile()
 
183
        inv.write_xml(inv_tmp)
 
184
        inv_tmp.seek(0)
 
185
        branch.inventory_store.add(inv_tmp, inv_id)
 
186
        mutter('new inventory_id is {%s}' % inv_id)
 
187
 
 
188
        branch._write_inventory(work_inv)
 
189
 
 
190
        if timestamp == None:
 
191
            timestamp = time.time()
 
192
 
 
193
        if committer == None:
 
194
            committer = username()
 
195
 
 
196
        if timezone == None:
 
197
            timezone = local_time_offset()
 
198
 
 
199
        mutter("building commit log message")
 
200
        rev = Revision(timestamp=timestamp,
 
201
                       timezone=timezone,
 
202
                       committer=committer,
 
203
                       precursor = branch.last_patch(),
 
204
                       message = message,
 
205
                       inventory_id=inv_id,
 
206
                       revision_id=rev_id)
 
207
 
 
208
        rev_tmp = tempfile.TemporaryFile()
 
209
        rev.write_xml(rev_tmp)
 
210
        rev_tmp.seek(0)
 
211
        branch.revision_store.add(rev_tmp, rev_id)
 
212
        mutter("new revision_id is {%s}" % rev_id)
 
213
 
 
214
        ## XXX: Everything up to here can simply be orphaned if we abort
 
215
        ## the commit; it will leave junk files behind but that doesn't
 
216
        ## matter.
 
217
 
 
218
        ## TODO: Read back the just-generated changeset, and make sure it
 
219
        ## applies and recreates the right state.
 
220
 
 
221
        ## TODO: Also calculate and store the inventory SHA1
 
222
        mutter("committing patch r%d" % (branch.revno() + 1))
 
223
 
 
224
        branch.append_revision(rev_id)
 
225
 
 
226
        if verbose:
 
227
            note("commited r%d" % branch.revno())
 
228
    finally:
 
229
        branch.unlock()
227
230
 
228
231
 
229
232