~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/check.py

  • Committer: Martin Pool
  • Date: 2005-08-26 02:31:37 UTC
  • Revision ID: mbp@sourcefrog.net-20050826023137-eb4b101cc92f9792
- ignore tags files

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# along with this program; if not, write to the Free Software
16
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
17
 
18
 
 
 
18
import bzrlib.ui
 
19
 
 
20
def _update_store_entry(obj, obj_id, branch, store_name, store):
 
21
    """This is just a meta-function, which handles both revision entries
 
22
    and inventory entries.
 
23
    """
 
24
    from bzrlib.trace import mutter
 
25
    import tempfile, os, errno
 
26
    from osutils import rename
 
27
    obj_tmp = tempfile.TemporaryFile()
 
28
    obj.write_xml(obj_tmp)
 
29
    obj_tmp.seek(0)
 
30
 
 
31
    tmpfd, tmp_path = tempfile.mkstemp(prefix=obj_id, suffix='.gz',
 
32
        dir=branch.controlfilename(store_name))
 
33
    os.close(tmpfd)
 
34
    try:
 
35
        orig_obj_path = branch.controlfilename([store_name, obj_id+'.gz'])
 
36
        # Remove the old entry out of the way
 
37
        rename(orig_obj_path, tmp_path)
 
38
        try:
 
39
            # TODO: We may need to handle the case where the old
 
40
            # entry was not compressed (and thus did not end with .gz)
 
41
 
 
42
            store.add(obj_tmp, obj_id) # Add the new one
 
43
            os.remove(tmp_path) # Remove the old name
 
44
            mutter('    Updated %s entry {%s}' % (store_name, obj_id))
 
45
        except:
 
46
            # On any exception, restore the old entry
 
47
            rename(tmp_path, orig_obj_path)
 
48
            raise
 
49
    finally:
 
50
        if os.path.exists(tmp_path):
 
51
            # Unfortunately, the next command might throw
 
52
            # an exception, which will mask a previous exception.
 
53
            os.remove(tmp_path)
 
54
        obj_tmp.close()
 
55
 
 
56
def _update_revision_entry(rev, branch):
 
57
    """After updating the values in a revision, make sure to
 
58
    write out the data, but try to do it in an atomic manner.
 
59
 
 
60
    :param rev:    The Revision object to store
 
61
    :param branch: The Branch object where this Revision is to be stored.
 
62
    """
 
63
    _update_store_entry(rev, rev.revision_id, branch,
 
64
            'revision-store', branch.revision_store)
 
65
 
 
66
def _update_inventory_entry(inv, inv_id, branch):
 
67
    """When an inventory has been modified (such as by adding a unique tree root)
 
68
    this atomically re-generates the file.
 
69
 
 
70
    :param inv:     The Inventory
 
71
    :param inv_id:  The inventory id for this inventory
 
72
    :param branch:  The Branch where this entry will be stored.
 
73
    """
 
74
    _update_store_entry(inv, inv_id, branch,
 
75
            'inventory-store', branch.inventory_store)
19
76
 
20
77
 
21
78
def check(branch):
22
79
    """Run consistency checks on a branch.
23
80
 
24
 
    TODO: Also check non-mailine revisions mentioned as parents.
 
81
    TODO: Also check non-mainline revisions mentioned as parents.
 
82
 
 
83
    TODO: Check for extra files in the control directory.
25
84
    """
26
85
    from bzrlib.trace import mutter
27
 
    from bzrlib.errors import BzrCheckError
 
86
    from bzrlib.errors import BzrCheckError, NoSuchRevision
28
87
    from bzrlib.osutils import fingerprint_file
29
 
    from bzrlib.progress import ProgressBar
 
88
    from bzrlib.inventory import ROOT_ID
 
89
    from bzrlib.branch import gen_root_id
30
90
 
31
91
    branch.lock_read()
32
92
 
33
93
    try:
34
 
        pb = ProgressBar(show_spinner=True)
35
94
        last_rev_id = None
36
95
 
37
96
        missing_inventory_sha_cnt = 0
38
97
        missing_revision_sha_cnt = 0
 
98
        missing_revision_cnt = 0
39
99
 
40
100
        history = branch.revision_history()
41
101
        revno = 0
42
102
        revcount = len(history)
 
103
        mismatch_inv_id = []
43
104
 
44
105
        # for all texts checked, text_id -> sha1
45
106
        checked_texts = {}
46
107
 
 
108
        progress = bzrlib.ui.ui_factory.progress_bar()
 
109
 
47
110
        for rev_id in history:
48
111
            revno += 1
49
 
            pb.update('checking revision', revno, revcount)
50
 
            mutter('    revision {%s}' % rev_id)
 
112
            progress.update('checking revision', revno, revcount)
 
113
            # mutter('    revision {%s}' % rev_id)
51
114
            rev = branch.get_revision(rev_id)
52
115
            if rev.revision_id != rev_id:
53
116
                raise BzrCheckError('wrong internal revision id in revision {%s}'
72
135
                        missing_revision_sha_cnt += 1
73
136
                        continue
74
137
                    prid = prr.revision_id
75
 
                    actual_sha = branch.get_revision_sha1(prid)
 
138
                    
 
139
                    try:
 
140
                        actual_sha = branch.get_revision_sha1(prid)
 
141
                    except NoSuchRevision:
 
142
                        missing_revision_cnt += 1
 
143
                        mutter("parent {%s} of {%s} not present in store",
 
144
                               prid, rev_id)
 
145
                        continue
 
146
                        
76
147
                    if prr.revision_sha1 != actual_sha:
77
148
                        raise BzrCheckError("mismatched revision sha1 for "
78
149
                                            "parent {%s} of {%s}: %s vs %s"
83
154
                                    "by {%s}"
84
155
                                    % (rev_id, last_rev_id))
85
156
 
 
157
            if rev.inventory_id != rev_id:
 
158
                mismatch_inv_id.append(rev_id)
 
159
 
86
160
            ## TODO: Check all the required fields are present on the revision.
87
161
 
88
162
            if rev.inventory_sha1:
110
184
            for file_id in inv:
111
185
                i += 1
112
186
                if i & 31 == 0:
113
 
                    pb.tick()
 
187
                    progress.tick()
114
188
 
115
189
                ie = inv[file_id]
116
190
 
139
213
                        raise BzrCheckError('directory {%s} has text in revision {%s}'
140
214
                                % (file_id, rev_id))
141
215
 
142
 
            pb.tick()
 
216
            progress.tick()
143
217
            for path, ie in inv.iter_entries():
144
218
                if path in seen_names:
145
219
                    raise BzrCheckError('duplicated path %s '
151
225
    finally:
152
226
        branch.unlock()
153
227
 
154
 
    pb.clear()
 
228
    progress.clear()
155
229
 
156
230
    print 'checked %d revisions, %d file texts' % (revcount, len(checked_texts))
157
231
    
161
235
    if missing_revision_sha_cnt:
162
236
        print '%d parent links are missing revision_sha1' % missing_revision_sha_cnt
163
237
 
164
 
    if (missing_inventory_sha_cnt
165
 
        or missing_revision_sha_cnt):
166
 
        print '  (use "bzr upgrade" to fix them)'
 
238
    if missing_revision_cnt:
 
239
        print '%d revisions are mentioned but not present' % missing_revision_cnt
 
240
 
 
241
    # stub this out for now because the main bzr branch has references
 
242
    # to revisions that aren't present in the store -- mbp 20050804
 
243
#    if (missing_inventory_sha_cnt
 
244
#        or missing_revision_sha_cnt):
 
245
#        print '  (use "bzr upgrade" to fix them)'
 
246
 
 
247
    if mismatch_inv_id:
 
248
        print '%d revisions have mismatched inventory ids:' % len(mismatch_inv_id)
 
249
        for rev_id in mismatch_inv_id:
 
250
            print '  ', rev_id