[Pkg-bazaar-commits] ./bzr/unstable r580: - Use explicit lock methods on a branch, rather than doing it
Martin Pool
mbp at sourcefrog.net
Fri Apr 10 08:19:41 UTC 2009
------------------------------------------------------------
revno: 580
committer: Martin Pool <mbp at sourcefrog.net>
timestamp: Mon 2005-05-30 11:37:52 +1000
message:
- 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.
modified:
bzrlib/branch.py
bzrlib/commands.py
bzrlib/commit.py
bzrlib/remotebranch.py
bzrlib/status.py
-------------- next part --------------
=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py 2005-05-27 05:23:57 +0000
+++ b/bzrlib/branch.py 2005-05-30 01:37:52 +0000
@@ -43,6 +43,29 @@
return remotebranch.RemoteBranch(f, **args)
else:
return Branch(f, **args)
+
+
+
+def with_writelock(method):
+ """Method decorator for functions run with the branch locked."""
+ def d(self, *a, **k):
+ # called with self set to the branch
+ self.lock('w')
+ try:
+ return method(self, *a, **k)
+ finally:
+ self.unlock()
+ return d
+
+
+def with_readlock(method):
+ def d(self, *a, **k):
+ self.lock('r')
+ try:
+ return method(self, *a, **k)
+ finally:
+ self.unlock()
+ return d
def find_branch_root(f=None):
@@ -87,16 +110,20 @@
Base directory of the branch.
_lock_mode
- None, or a duple with 'r' or 'w' for the first element and a positive
- count for the second.
+ None, or 'r' or 'w'
+
+ _lock_count
+ If _lock_mode is true, a positive count of the number of times the
+ lock has been taken.
_lockfile
Open file used for locking.
"""
base = None
_lock_mode = None
+ _lock_count = None
- def __init__(self, base, init=False, find_root=True, lock_mode='w'):
+ def __init__(self, base, init=False, find_root=True):
"""Create new branch object at a particular location.
base -- Base directory for the branch.
@@ -125,7 +152,6 @@
'current bzr can only operate from top-of-tree'])
self._check_format()
self._lockfile = self.controlfile('branch-lock', 'wb')
- self.lock(lock_mode)
self.text_store = ImmutableStore(self.controlfilename('text-store'))
self.revision_store = ImmutableStore(self.controlfilename('revision-store'))
@@ -148,36 +174,36 @@
def lock(self, mode):
if self._lock_mode:
- raise BzrError('branch %r is already locked: %r' % (self, self._lock_mode))
-
- from bzrlib.lock import lock, LOCK_SH, LOCK_EX
- if mode == 'r':
- m = LOCK_SH
- elif mode == 'w':
- m = LOCK_EX
+ if mode == 'w' and cur_lm == 'r':
+ raise BzrError("can't upgrade to a write lock")
+
+ assert self._lock_count >= 1
+ self._lock_count += 1
else:
- raise ValueError('invalid lock mode %r' % mode)
-
- lock(self._lockfile, m)
- self._lock_mode = (mode, 1)
+ from bzrlib.lock import lock, LOCK_SH, LOCK_EX
+ if mode == 'r':
+ m = LOCK_SH
+ elif mode == 'w':
+ m = LOCK_EX
+ else:
+ raise ValueError('invalid lock mode %r' % mode)
+
+ lock(self._lockfile, m)
+ self._lock_mode = mode
+ self._lock_count = 1
def unlock(self):
if not self._lock_mode:
raise BzrError('branch %r is not locked' % (self))
- from bzrlib.lock import unlock
- unlock(self._lockfile)
- self._lock_mode = None
-
-
- def _need_readlock(self):
- if not self._lock_mode:
- raise BzrError('need read lock on branch, only have %r' % self._lockmode)
-
-
- def _need_writelock(self):
- if (self._lock_mode == None) or (self._lock_mode[0] != 'w'):
- raise BzrError('need write lock on branch, only have %r' % self._lockmode)
+
+ if self._lock_count > 1:
+ self._lock_count -= 1
+ else:
+ assert self._lock_count == 1
+ from bzrlib.lock import unlock
+ unlock(self._lockfile)
+ self._lock_mode = self._lock_count = None
def abspath(self, name):
@@ -268,9 +294,10 @@
'or remove the .bzr directory and "bzr init" again'])
+
+ @with_readlock
def read_working_inventory(self):
"""Read the working inventory."""
- self._need_readlock()
before = time.time()
# ElementTree does its own conversion from UTF-8, so open in
# binary.
@@ -278,7 +305,7 @@
mutter("loaded inventory of %d items in %f"
% (len(inv), time.time() - before))
return inv
-
+
def _write_inventory(self, inv):
"""Update the working inventory.
@@ -286,7 +313,6 @@
That is to say, the inventory describing changes underway, that
will be committed to the next revision.
"""
- self._need_writelock()
## TODO: factor out to atomicfile? is rename safe on windows?
## TODO: Maybe some kind of clean/dirty marker on inventory?
tmpfname = self.controlfilename('inventory.tmp')
@@ -298,12 +324,13 @@
os.remove(inv_fname)
os.rename(tmpfname, inv_fname)
mutter('wrote working inventory')
-
+
inventory = property(read_working_inventory, _write_inventory, None,
"""Inventory for the working copy.""")
+ @with_writelock
def add(self, files, verbose=False, ids=None):
"""Make files versioned.
@@ -324,8 +351,6 @@
add all non-ignored children. Perhaps do that in a
higher-level method.
"""
- self._need_writelock()
-
# TODO: Re-adding a file that is removed in the working copy
# should probably put it back with the previous ID.
if isinstance(files, types.StringTypes):
@@ -338,7 +363,7 @@
ids = [None] * len(files)
else:
assert(len(ids) == len(files))
-
+
inv = self.read_working_inventory()
for f,file_id in zip(files, ids):
if is_control_file(f):
@@ -348,7 +373,7 @@
if len(fp) == 0:
raise BzrError("cannot add top-level %r" % f)
-
+
fullpath = os.path.normpath(self.abspath(f))
try:
@@ -356,7 +381,7 @@
except OSError:
# maybe something better?
raise BzrError('cannot add: not a regular file or directory: %s' % quotefn(f))
-
+
if kind != 'file' and kind != 'directory':
raise BzrError('cannot add: not a regular file or directory: %s' % quotefn(f))
@@ -366,23 +391,23 @@
if verbose:
show_status('A', kind, quotefn(f))
-
+
mutter("add file %s file_id:{%s} kind=%r" % (f, file_id, kind))
+
+ self._write_inventory(inv)
- self._write_inventory(inv)
-
def print_file(self, file, revno):
"""Print `file` to stdout."""
- self._need_readlock()
tree = self.revision_tree(self.lookup_revision(revno))
# use inventory as it was in that revision
file_id = tree.inventory.path2id(file)
if not file_id:
raise BzrError("%r is not present in revision %d" % (file, revno))
tree.print_file(file_id)
-
-
+
+
+ @with_writelock
def remove(self, files, verbose=False):
"""Mark nominated files for removal from the inventory.
@@ -399,11 +424,9 @@
"""
## TODO: Normalize names
## TODO: Remove nested loops; better scalability
- self._need_writelock()
-
if isinstance(files, types.StringTypes):
files = [files]
-
+
tree = self.working_tree()
inv = tree.inventory
@@ -424,6 +447,7 @@
self._write_inventory(inv)
+
def set_inventory(self, new_inventory_list):
inv = Inventory()
for path, file_id, parent, kind in new_inventory_list:
@@ -474,7 +498,6 @@
def get_revision(self, revision_id):
"""Return the Revision object for a named revision"""
- self._need_readlock()
r = Revision.read_xml(self.revision_store[revision_id])
assert r.revision_id == revision_id
return r
@@ -486,27 +509,25 @@
TODO: Perhaps for this and similar methods, take a revision
parameter which can be either an integer revno or a
string hash."""
- self._need_readlock()
i = Inventory.read_xml(self.inventory_store[inventory_id])
return i
def get_revision_inventory(self, revision_id):
"""Return inventory of a past revision."""
- self._need_readlock()
if revision_id == None:
return Inventory()
else:
return self.get_inventory(self.get_revision(revision_id).inventory_id)
+ @with_readlock
def revision_history(self):
"""Return sequence of revision hashes on to this branch.
>>> ScratchBranch().revision_history()
[]
"""
- self._need_readlock()
return [l.rstrip('\r\n') for l in self.controlfile('revision-history', 'r').readlines()]
@@ -576,7 +597,6 @@
an `EmptyTree` is returned."""
# TODO: refactor this to use an existing revision object
# so we don't need to read it in twice.
- self._need_readlock()
if revision_id == None:
return EmptyTree()
else:
@@ -603,19 +623,19 @@
+ @with_writelock
def rename_one(self, from_rel, to_rel):
"""Rename one file.
This can change the directory or the filename or both.
"""
- self._need_writelock()
tree = self.working_tree()
inv = tree.inventory
if not tree.has_filename(from_rel):
raise BzrError("can't rename: old working file %r does not exist" % from_rel)
if tree.has_filename(to_rel):
raise BzrError("can't rename: new working file %r already exists" % to_rel)
-
+
file_id = inv.path2id(from_rel)
if file_id == None:
raise BzrError("can't rename: old name %r is not versioned" % from_rel)
@@ -634,11 +654,11 @@
mutter(" to_rel %r" % to_rel)
mutter(" to_dir %r" % to_dir)
mutter(" to_dir_id {%s}" % to_dir_id)
-
+
inv.rename(file_id, to_dir_id, to_tail)
print "%s => %s" % (from_rel, to_rel)
-
+
from_abs = self.abspath(from_rel)
to_abs = self.abspath(to_rel)
try:
@@ -649,9 +669,10 @@
["rename rolled back"])
self._write_inventory(inv)
-
-
-
+
+
+
+ @with_writelock
def move(self, from_paths, to_name):
"""Rename files.
@@ -663,7 +684,6 @@
Note that to_name is only the last component of the new name;
this doesn't change the directory.
"""
- self._need_writelock()
## TODO: Option to move IDs only
assert not isinstance(from_paths, basestring)
tree = self.working_tree()
=== modified file 'bzrlib/commands.py'
--- a/bzrlib/commands.py 2005-05-27 04:08:47 +0000
+++ b/bzrlib/commands.py 2005-05-30 01:37:52 +0000
@@ -263,14 +263,14 @@
def run(self, all=False, show_ids=False, file_list=None):
if file_list:
- b = Branch(file_list[0], lock_mode='r')
+ b = Branch(file_list[0])
file_list = [b.relpath(x) for x in file_list]
# special case: only one path was given and it's the root
# of the branch
if file_list == ['']:
file_list = None
else:
- b = Branch('.', lock_mode='r')
+ b = Branch('.')
import status
status.show_status(b, show_unchanged=all, show_ids=show_ids,
specific_files=file_list)
@@ -531,13 +531,13 @@
from bzrlib import find_branch
if file_list:
- b = find_branch(file_list[0], lock_mode='r')
+ b = find_branch(file_list[0])
file_list = [b.relpath(f) for f in file_list]
if file_list == ['']:
# just pointing to top-of-tree
file_list = None
else:
- b = Branch('.', lock_mode='r')
+ b = Branch('.')
show_diff(b, revision, specific_files=file_list,
external_diff_options=diff_options)
@@ -652,14 +652,14 @@
direction = (forward and 'forward') or 'reverse'
if filename:
- b = find_branch(filename, lock_mode='r')
+ b = find_branch(filename)
fp = b.relpath(filename)
if fp:
file_id = b.read_working_inventory().path2id(fp)
else:
file_id = None # points to branch root
else:
- b = find_branch('.', lock_mode='r')
+ b = find_branch('.')
file_id = None
if revision == None:
@@ -693,7 +693,7 @@
hidden = True
takes_args = ["filename"]
def run(self, filename):
- b = Branch(filename, lock_mode='r')
+ b = Branch(filename)
inv = b.read_working_inventory()
file_id = inv.path2id(b.relpath(filename))
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
=== modified file 'bzrlib/commit.py'
--- a/bzrlib/commit.py 2005-05-17 06:51:31 +0000
+++ b/bzrlib/commit.py 2005-05-30 01:37:52 +0000
@@ -64,166 +64,169 @@
from revision import Revision
from trace import mutter, note
- branch._need_writelock()
-
- # First walk over the working inventory; and both update that
- # and also build a new revision inventory. The revision
- # inventory needs to hold the text-id, sha1 and size of the
- # actual file versions committed in the revision. (These are
- # not present in the working inventory.) We also need to
- # detect missing/deleted files, and remove them from the
- # working inventory.
-
- work_tree = branch.working_tree()
- work_inv = work_tree.inventory
- inv = Inventory()
- basis = branch.basis_tree()
- basis_inv = basis.inventory
- missing_ids = []
-
- if verbose:
- note('looking for changes...')
-
- for path, entry in work_inv.iter_entries():
- ## TODO: Check that the file kind has not changed from the previous
- ## revision of this file (if any).
-
- entry = entry.copy()
-
- p = branch.abspath(path)
- file_id = entry.file_id
- mutter('commit prep file %s, id %r ' % (p, file_id))
-
- if specific_files and not is_inside_any(specific_files, path):
+ branch.lock('w')
+
+ try:
+ # First walk over the working inventory; and both update that
+ # and also build a new revision inventory. The revision
+ # inventory needs to hold the text-id, sha1 and size of the
+ # actual file versions committed in the revision. (These are
+ # not present in the working inventory.) We also need to
+ # detect missing/deleted files, and remove them from the
+ # working inventory.
+
+ work_tree = branch.working_tree()
+ work_inv = work_tree.inventory
+ inv = Inventory()
+ basis = branch.basis_tree()
+ basis_inv = basis.inventory
+ missing_ids = []
+
+ if verbose:
+ note('looking for changes...')
+
+ for path, entry in work_inv.iter_entries():
+ ## TODO: Check that the file kind has not changed from the previous
+ ## revision of this file (if any).
+
+ entry = entry.copy()
+
+ p = branch.abspath(path)
+ file_id = entry.file_id
+ mutter('commit prep file %s, id %r ' % (p, file_id))
+
+ if specific_files and not is_inside_any(specific_files, path):
+ if basis_inv.has_id(file_id):
+ # carry over with previous state
+ inv.add(basis_inv[file_id].copy())
+ else:
+ # omit this from committed inventory
+ pass
+ continue
+
+ if not work_tree.has_id(file_id):
+ if verbose:
+ print('deleted %s%s' % (path, kind_marker(entry.kind)))
+ mutter(" file is missing, removing from inventory")
+ missing_ids.append(file_id)
+ continue
+
+ inv.add(entry)
+
if basis_inv.has_id(file_id):
- # carry over with previous state
- inv.add(basis_inv[file_id].copy())
- else:
- # omit this from committed inventory
- pass
- continue
-
- if not work_tree.has_id(file_id):
- if verbose:
- print('deleted %s%s' % (path, kind_marker(entry.kind)))
- mutter(" file is missing, removing from inventory")
- missing_ids.append(file_id)
- continue
-
- inv.add(entry)
-
- if basis_inv.has_id(file_id):
- old_kind = basis_inv[file_id].kind
- if old_kind != entry.kind:
- raise BzrError("entry %r changed kind from %r to %r"
- % (file_id, old_kind, entry.kind))
-
- if entry.kind == 'directory':
- if not isdir(p):
- raise BzrError("%s is entered as directory but not a directory"
- % quotefn(p))
- elif entry.kind == 'file':
- if not isfile(p):
- raise BzrError("%s is entered as file but is not a file" % quotefn(p))
-
- new_sha1 = work_tree.get_file_sha1(file_id)
-
- old_ie = basis_inv.has_id(file_id) and basis_inv[file_id]
- if (old_ie
- and old_ie.text_sha1 == new_sha1):
- ## assert content == basis.get_file(file_id).read()
- entry.text_id = old_ie.text_id
- entry.text_sha1 = new_sha1
- entry.text_size = old_ie.text_size
- mutter(' unchanged from previous text_id {%s}' %
- entry.text_id)
- else:
- content = file(p, 'rb').read()
-
- # calculate the sha again, just in case the file contents
- # changed since we updated the cache
- entry.text_sha1 = sha_string(content)
- entry.text_size = len(content)
-
- entry.text_id = gen_file_id(entry.name)
- branch.text_store.add(content, entry.text_id)
- mutter(' stored with text_id {%s}' % entry.text_id)
- if verbose:
- if not old_ie:
- print('added %s' % path)
- elif (old_ie.name == entry.name
- and old_ie.parent_id == entry.parent_id):
- print('modified %s' % path)
- else:
- print('renamed %s' % path)
-
-
- for file_id in missing_ids:
- # Any files that have been deleted are now removed from the
- # working inventory. Files that were not selected for commit
- # are left as they were in the working inventory and ommitted
- # from the revision inventory.
-
- # have to do this later so we don't mess up the iterator.
- # since parents may be removed before their children we
- # have to test.
-
- # FIXME: There's probably a better way to do this; perhaps
- # the workingtree should know how to filter itbranch.
- if work_inv.has_id(file_id):
- del work_inv[file_id]
-
-
- if rev_id is None:
- rev_id = _gen_revision_id(time.time())
- inv_id = rev_id
-
- inv_tmp = tempfile.TemporaryFile()
- inv.write_xml(inv_tmp)
- inv_tmp.seek(0)
- branch.inventory_store.add(inv_tmp, inv_id)
- mutter('new inventory_id is {%s}' % inv_id)
-
- branch._write_inventory(work_inv)
-
- if timestamp == None:
- timestamp = time.time()
-
- if committer == None:
- committer = username()
-
- if timezone == None:
- timezone = local_time_offset()
-
- mutter("building commit log message")
- rev = Revision(timestamp=timestamp,
- timezone=timezone,
- committer=committer,
- precursor = branch.last_patch(),
- message = message,
- inventory_id=inv_id,
- revision_id=rev_id)
-
- rev_tmp = tempfile.TemporaryFile()
- rev.write_xml(rev_tmp)
- rev_tmp.seek(0)
- branch.revision_store.add(rev_tmp, rev_id)
- mutter("new revision_id is {%s}" % rev_id)
-
- ## XXX: Everything up to here can simply be orphaned if we abort
- ## the commit; it will leave junk files behind but that doesn't
- ## matter.
-
- ## TODO: Read back the just-generated changeset, and make sure it
- ## applies and recreates the right state.
-
- ## TODO: Also calculate and store the inventory SHA1
- mutter("committing patch r%d" % (branch.revno() + 1))
-
- branch.append_revision(rev_id)
-
- if verbose:
- note("commited r%d" % branch.revno())
+ old_kind = basis_inv[file_id].kind
+ if old_kind != entry.kind:
+ raise BzrError("entry %r changed kind from %r to %r"
+ % (file_id, old_kind, entry.kind))
+
+ if entry.kind == 'directory':
+ if not isdir(p):
+ raise BzrError("%s is entered as directory but not a directory"
+ % quotefn(p))
+ elif entry.kind == 'file':
+ if not isfile(p):
+ raise BzrError("%s is entered as file but is not a file" % quotefn(p))
+
+ new_sha1 = work_tree.get_file_sha1(file_id)
+
+ old_ie = basis_inv.has_id(file_id) and basis_inv[file_id]
+ if (old_ie
+ and old_ie.text_sha1 == new_sha1):
+ ## assert content == basis.get_file(file_id).read()
+ entry.text_id = old_ie.text_id
+ entry.text_sha1 = new_sha1
+ entry.text_size = old_ie.text_size
+ mutter(' unchanged from previous text_id {%s}' %
+ entry.text_id)
+ else:
+ content = file(p, 'rb').read()
+
+ # calculate the sha again, just in case the file contents
+ # changed since we updated the cache
+ entry.text_sha1 = sha_string(content)
+ entry.text_size = len(content)
+
+ entry.text_id = gen_file_id(entry.name)
+ branch.text_store.add(content, entry.text_id)
+ mutter(' stored with text_id {%s}' % entry.text_id)
+ if verbose:
+ if not old_ie:
+ print('added %s' % path)
+ elif (old_ie.name == entry.name
+ and old_ie.parent_id == entry.parent_id):
+ print('modified %s' % path)
+ else:
+ print('renamed %s' % path)
+
+
+ for file_id in missing_ids:
+ # Any files that have been deleted are now removed from the
+ # working inventory. Files that were not selected for commit
+ # are left as they were in the working inventory and ommitted
+ # from the revision inventory.
+
+ # have to do this later so we don't mess up the iterator.
+ # since parents may be removed before their children we
+ # have to test.
+
+ # FIXME: There's probably a better way to do this; perhaps
+ # the workingtree should know how to filter itbranch.
+ if work_inv.has_id(file_id):
+ del work_inv[file_id]
+
+
+ if rev_id is None:
+ rev_id = _gen_revision_id(time.time())
+ inv_id = rev_id
+
+ inv_tmp = tempfile.TemporaryFile()
+ inv.write_xml(inv_tmp)
+ inv_tmp.seek(0)
+ branch.inventory_store.add(inv_tmp, inv_id)
+ mutter('new inventory_id is {%s}' % inv_id)
+
+ branch._write_inventory(work_inv)
+
+ if timestamp == None:
+ timestamp = time.time()
+
+ if committer == None:
+ committer = username()
+
+ if timezone == None:
+ timezone = local_time_offset()
+
+ mutter("building commit log message")
+ rev = Revision(timestamp=timestamp,
+ timezone=timezone,
+ committer=committer,
+ precursor = branch.last_patch(),
+ message = message,
+ inventory_id=inv_id,
+ revision_id=rev_id)
+
+ rev_tmp = tempfile.TemporaryFile()
+ rev.write_xml(rev_tmp)
+ rev_tmp.seek(0)
+ branch.revision_store.add(rev_tmp, rev_id)
+ mutter("new revision_id is {%s}" % rev_id)
+
+ ## XXX: Everything up to here can simply be orphaned if we abort
+ ## the commit; it will leave junk files behind but that doesn't
+ ## matter.
+
+ ## TODO: Read back the just-generated changeset, and make sure it
+ ## applies and recreates the right state.
+
+ ## TODO: Also calculate and store the inventory SHA1
+ mutter("committing patch r%d" % (branch.revno() + 1))
+
+ branch.append_revision(rev_id)
+
+ if verbose:
+ note("commited r%d" % branch.revno())
+ finally:
+ branch.unlock()
=== modified file 'bzrlib/remotebranch.py'
--- a/bzrlib/remotebranch.py 2005-05-26 02:13:57 +0000
+++ b/bzrlib/remotebranch.py 2005-05-30 01:37:52 +0000
@@ -99,7 +99,7 @@
class RemoteBranch(Branch):
- def __init__(self, baseurl, find_root=True, lock_mode='r'):
+ def __init__(self, baseurl, find_root=True):
"""Create new proxy for a remote branch."""
if lock_mode not in ('', 'r'):
raise BzrError('lock mode %r is not supported for remote branches'
@@ -124,12 +124,14 @@
raise BzrError("file mode %r not supported for remote branches" % mode)
return get_url(self.baseurl + '/.bzr/' + filename, False)
- def _need_readlock(self):
- # remote branch always safe for read
+
+ def lock(self, mode):
+ if mode != 'r':
+ raise BzrError('lock mode %r not supported for remote branch %r' % (mode, self))
+
+ def unlock(self):
pass
-
- def _need_writelock(self):
- raise BzrError("cannot get write lock on HTTP remote branch")
+
def relpath(self, path):
if not path.startswith(self.baseurl):
=== modified file 'bzrlib/status.py'
--- a/bzrlib/status.py 2005-05-11 08:11:37 +0000
+++ b/bzrlib/status.py 2005-05-30 01:37:52 +0000
@@ -28,28 +28,32 @@
If set, only show the status of files in this list.
"""
import sys
- import diff
-
- branch._need_readlock()
-
- old = branch.basis_tree()
- new = branch.working_tree()
-
- delta = diff.compare_trees(old, new, want_unchanged=show_unchanged,
- specific_files=specific_files)
-
- delta.show(sys.stdout, show_ids=show_ids,
- show_unchanged=show_unchanged)
-
- unknowns = new.unknowns()
- done_header = False
- for path in unknowns:
- # FIXME: Should also match if the unknown file is within a
- # specified directory.
- if specific_files:
- if path not in specific_files:
- continue
- if not done_header:
- print 'unknown:'
- done_header = True
- print ' ', path
+ from bzrlib.diff import compare_trees
+
+ branch.lock('r')
+ try:
+
+ old = branch.basis_tree()
+ new = branch.working_tree()
+
+ delta = compare_trees(old, new, want_unchanged=show_unchanged,
+ specific_files=specific_files)
+
+ delta.show(sys.stdout, show_ids=show_ids,
+ show_unchanged=show_unchanged)
+
+ unknowns = new.unknowns()
+ done_header = False
+ for path in unknowns:
+ # FIXME: Should also match if the unknown file is within a
+ # specified directory.
+ if specific_files:
+ if path not in specific_files:
+ continue
+ if not done_header:
+ print 'unknown:'
+ done_header = True
+ print ' ', path
+ finally:
+ branch.unlock()
+
More information about the Pkg-bazaar-commits
mailing list