1
# Copyright (C) 2006 by Canonical Ltd
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.
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.
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
17
"""DirState objects record the state of a directory and its bzr metadata."""
29
import bzrlib.inventory
30
from bzrlib.osutils import pathjoin, sha_file, sha_string, walkdirs
35
class DirState(object):
36
"""Record directory and metadata state for fast access.
38
A dirstate is a specialised data structure for managing local working
39
tree state information. Its not yet well defined whether it is platform
40
specific, and if it is how we detect/parameterise that.
43
_kind_to_minikind = {'file':'f', 'directory':'d', 'symlink':'l'}
44
_minikind_to_kind = {'f':'file', 'd':'directory', 'l':'symlink'}
48
def from_tree(tree, base_path):
49
"""Create a dirstate from a bzr Tree and a local disk path.
51
:param tree: The tree which should provide parent information and
53
:param base_path: The local path to access the local fs data for this tree.
54
This is not accessed via the tree object because we want to be able
55
to seed DirStates from RevisionTrees during checkout. Possibly
56
a better model is to start with an empty dirstate and populate it
57
during the checkout operation, but that will require looking at the
58
behaviour of set_inventory etc. which is not in scope yet - and is
59
potentially very expensive as it requires an entire scan, or an
66
_encode = base64.encodestring
68
parent_ids = tree.get_parent_ids()
69
num_parents = len(parent_ids)
71
raise ValueError('Cannot handle more than 3 parents')
74
for parent_id in parent_ids:
75
parent_trees.append(tree.branch.repository.revision_tree(parent_id))
77
# FIXME: is this utf8 safe?
78
lines.append('\0'.join([str(num_parents)] + parent_ids))
80
to_minikind = DirState._kind_to_minikind
82
st = os.lstat(base_path)
83
null_parent_info = '\0'.join((
91
#, 'd', gen_root_id().encode('utf8')
94
, 'd', tree.inventory.root.file_id.encode('utf8')
98
] + [null_parent_info]*num_parents
99
# disabled because the root entry has no revision attribute set.
100
# for parent_tree in parent_trees:
101
# root_info.append('\0'.join((
102
# parent_tree.inventory.root.revision.encode('utf8'),
110
lines.append('\0'.join(root_info))
112
test_sha = sha.new('').hexdigest()
115
for block in walkdirs(base_path):
118
for relpath, name, kind, st, abspath in block:
120
symlink_target = None
121
dirname, basename = os.path.split(relpath.encode('utf8'))
123
#s = sha_file(open(abspath, 'rb'))
125
elif kind == 'directory':
126
if name in ('.bzr', '.hg', 'CVS', '.svn', '_svn'):
127
# Skip this, and all children
128
to_remove.append((relpath, name, kind, st, abspath))
131
elif kind == 'symlink':
132
s = os.readlink(abspath)
142
, 'n' # Not executable
152
, 'n' # Not executable
155
for count in xrange(2,num_parents):
156
parent_info.append(null_parent_info)
157
lines.append('\0'.join([
160
, gen_file_id(name).encode('utf8')
167
# It isn't safe to remove entries while we are iterating
168
# over the same list, so remove them now
169
for entry in to_remove:
172
output_lines = ['#bzr dirstate flat format 1\n']
174
lines.append('') # a final newline
175
inventory_text = '\0\n\0'.join(lines)
176
output_lines.append('adler32: %s\n' % (zlib.adler32(inventory_text),))
177
# -2, 1 for num parents, 1 for final newline
178
num_entries = len(lines)-2
179
output_lines.append('num_entries: %s\n' % (num_entries,))
180
output_lines.append(inventory_text)
182
result.lines = output_lines
186
"""Serialise the entire dirstate to a sequence of lines."""
189
'#bzr dirstate flat format 1\n',
193
'\x00\x00\x00d\x00TREE_ROOT\x004096\x00AAAQAETIF65EyBeuAAADAQAQQxsAAEHt\x00\x00\n',
197
def pack_stat(st, _encode=base64.encodestring, _pack=struct.pack):
198
"""Convert stat values into a packed representation."""
199
# jam 20060614 it isn't really worth removing more entries if we
200
# are going to leave it in packed form.
201
# With only st_mtime and st_mode filesize is 5.5M and read time is 275ms
202
# With all entries filesize is 5.9M and read time is mabye 280ms
203
# well within the noise margin
205
# base64.encode always adds a final newline, so strip it off
206
return _encode(_pack('>llllll'
207
, st.st_size, st.st_mtime, st.st_ctime
208
, st.st_dev, st.st_ino, st.st_mode))[:-1]