80
81
def tree_files_for_add(file_list):
81
"""Add handles files a bit differently so it a custom implementation."""
83
Return a tree and list of absolute paths from a file list.
85
Similar to tree_files, but add handles files a bit differently, so it a
86
custom implementation. In particular, MutableTreeTree.smart_add expects
87
absolute paths, which it immediately converts to relative paths.
89
# FIXME Would be nice to just return the relative paths like
90
# internal_tree_files does, but there are a large number of unit tests
91
# that assume the current interface to mutabletree.smart_add
83
tree = WorkingTree.open_containing(file_list[0])[0]
93
tree, relpath = WorkingTree.open_containing(file_list[0])
84
94
if tree.supports_views():
85
95
view_files = tree.views.lookup_view()
86
for filename in file_list:
87
if not osutils.is_inside_any(view_files, filename):
88
raise errors.FileOutsideView(filename, view_files)
97
for filename in file_list:
98
if not osutils.is_inside_any(view_files, filename):
99
raise errors.FileOutsideView(filename, view_files)
100
file_list = file_list[:]
101
file_list[0] = tree.abspath(relpath)
90
103
tree = WorkingTree.open_containing(u'.')[0]
91
104
if tree.supports_views():
2146
2197
dir, relpath = bzrdir.BzrDir.open_containing(location)
2147
2198
b = dir.open_branch()
2151
2199
rev1, rev2 = _get_revision_range(revision, b, self.name())
2201
# Decide on the type of delta & diff filtering to use
2202
# TODO: add an --all-files option to make this configurable & consistent
2210
diff_type = 'partial'
2216
# Build the log formatter
2152
2217
if log_format is None:
2153
2218
log_format = log.log_formatter_registry.get_default(b)
2155
2219
lf = log_format(show_ids=show_ids, to_file=self.outf,
2156
2220
show_timezone=timezone,
2157
2221
delta_format=get_verbosity_level(),
2164
direction=direction,
2165
start_revision=rev1,
2169
show_diff=show_diff)
2223
show_advice=levels is None)
2225
# Choose the algorithm for doing the logging. It's annoying
2226
# having multiple code paths like this but necessary until
2227
# the underlying repository format is faster at generating
2228
# deltas or can provide everything we need from the indices.
2229
# The default algorithm - match-using-deltas - works for
2230
# multiple files and directories and is faster for small
2231
# amounts of history (200 revisions say). However, it's too
2232
# slow for logging a single file in a repository with deep
2233
# history, i.e. > 10K revisions. In the spirit of "do no
2234
# evil when adding features", we continue to use the
2235
# original algorithm - per-file-graph - for the "single
2236
# file that isn't a directory without showing a delta" case.
2237
partial_history = revision and b.repository._format.supports_chks
2238
match_using_deltas = (len(file_ids) != 1 or filter_by_dir
2239
or delta_type or partial_history)
2241
# Build the LogRequest and execute it
2242
if len(file_ids) == 0:
2244
rqst = make_log_request_dict(
2245
direction=direction, specific_fileids=file_ids,
2246
start_revision=rev1, end_revision=rev2, limit=limit,
2247
message_search=message, delta_type=delta_type,
2248
diff_type=diff_type, _match_using_deltas=match_using_deltas)
2249
Logger(b, rqst).show(lf)
2631
2729
class cmd_commit(Command):
2632
2730
"""Commit changes into a new revision.
2634
If no arguments are given, the entire tree is committed.
2636
If selected files are specified, only changes to those files are
2637
committed. If a directory is specified then the directory and everything
2638
within it is committed.
2640
When excludes are given, they take precedence over selected files.
2641
For example, too commit only changes within foo, but not changes within
2644
bzr commit foo -x foo/bar
2646
If author of the change is not the same person as the committer, you can
2647
specify the author's name using the --author option. The name should be
2648
in the same format as a committer-id, e.g. "John Doe <jdoe@example.com>".
2649
If there is more than one author of the change you can specify the option
2650
multiple times, once for each author.
2652
A selected-file commit may fail in some cases where the committed
2653
tree would be invalid. Consider::
2658
bzr commit foo -m "committing foo"
2659
bzr mv foo/bar foo/baz
2662
bzr commit foo/bar -m "committing bar but not baz"
2664
In the example above, the last commit will fail by design. This gives
2665
the user the opportunity to decide whether they want to commit the
2666
rename at the same time, separately first, or not at all. (As a general
2667
rule, when in doubt, Bazaar has a policy of Doing the Safe Thing.)
2669
Note: A selected-file commit after a merge is not yet supported.
2732
An explanatory message needs to be given for each commit. This is
2733
often done by using the --message option (getting the message from the
2734
command line) or by using the --file option (getting the message from
2735
a file). If neither of these options is given, an editor is opened for
2736
the user to enter the message. To see the changed files in the
2737
boilerplate text loaded into the editor, use the --show-diff option.
2739
By default, the entire tree is committed and the person doing the
2740
commit is assumed to be the author. These defaults can be overridden
2745
If selected files are specified, only changes to those files are
2746
committed. If a directory is specified then the directory and
2747
everything within it is committed.
2749
When excludes are given, they take precedence over selected files.
2750
For example, to commit only changes within foo, but not changes
2753
bzr commit foo -x foo/bar
2755
A selective commit after a merge is not yet supported.
2759
If the author of the change is not the same person as the committer,
2760
you can specify the author's name using the --author option. The
2761
name should be in the same format as a committer-id, e.g.
2762
"John Doe <jdoe@example.com>". If there is more than one author of
2763
the change you can specify the option multiple times, once for each
2768
A common mistake is to forget to add a new file or directory before
2769
running the commit command. The --strict option checks for unknown
2770
files and aborts the commit if any are found. More advanced pre-commit
2771
checks can be implemented by defining hooks. See ``bzr help hooks``
2776
If you accidentially commit the wrong changes or make a spelling
2777
mistake in the commit message say, you can use the uncommit command
2778
to undo it. See ``bzr help uncommit`` for details.
2780
Hooks can also be configured to run after a commit. This allows you
2781
to trigger updates to external systems like bug trackers. The --fixes
2782
option can be used to record the association between a revision and
2783
one or more bugs. See ``bzr help bugs`` for details.
2785
A selective commit may fail in some cases where the committed
2786
tree would be invalid. Consider::
2791
bzr commit foo -m "committing foo"
2792
bzr mv foo/bar foo/baz
2795
bzr commit foo/bar -m "committing bar but not baz"
2797
In the example above, the last commit will fail by design. This gives
2798
the user the opportunity to decide whether they want to commit the
2799
rename at the same time, separately first, or not at all. (As a general
2800
rule, when in doubt, Bazaar has a policy of Doing the Safe Thing.)
2671
2802
# TODO: Run hooks on tree to-be-committed, and after commit.
4434
def run_smart_server(self, smart_server):
4435
"""Run 'smart_server' forever, with no UI output at all."""
4436
# For the duration of this server, no UI output is permitted. note
4437
# that this may cause problems with blackbox tests. This should be
4438
# changed with care though, as we dont want to use bandwidth sending
4439
# progress over stderr to smart server clients!
4440
from bzrlib import lockdir
4441
old_factory = ui.ui_factory
4442
old_lockdir_timeout = lockdir._DEFAULT_TIMEOUT_SECONDS
4444
ui.ui_factory = ui.SilentUIFactory()
4445
lockdir._DEFAULT_TIMEOUT_SECONDS = 0
4446
smart_server.serve()
4448
ui.ui_factory = old_factory
4449
lockdir._DEFAULT_TIMEOUT_SECONDS = old_lockdir_timeout
4451
4574
def get_host_and_port(self, port):
4452
4575
"""Return the host and port to run the smart server on.
4454
If 'port' is None, the default host (`medium.BZR_DEFAULT_INTERFACE`)
4455
and port (`medium.BZR_DEFAULT_PORT`) will be used.
4577
If 'port' is None, None will be returned for the host and port.
4457
4579
If 'port' has a colon in it, the string before the colon will be
4458
4580
interpreted as the host.
4461
4583
:return: A tuple of (host, port), where 'host' is a host name or IP,
4462
4584
and port is an integer TCP/IP port.
4464
from bzrlib.smart import medium
4465
host = medium.BZR_DEFAULT_INTERFACE
4467
port = medium.BZR_DEFAULT_PORT
4587
if port is not None:
4469
4588
if ':' in port:
4470
4589
host, port = port.split(':')
4471
4590
port = int(port)
4472
4591
return host, port
4474
def get_smart_server(self, transport, inet, port):
4475
"""Construct a smart server.
4477
:param transport: The base transport from which branches will be
4479
:param inet: If True, serve over stdin and stdout. Used for running
4481
:param port: The port to listen on. By default, it's `
4482
medium.BZR_DEFAULT_PORT`. See `get_host_and_port` for more
4484
:return: A smart server.
4486
from bzrlib.smart import medium, server
4488
smart_server = medium.SmartServerPipeStreamMedium(
4489
sys.stdin, sys.stdout, transport)
4491
host, port = self.get_host_and_port(port)
4492
smart_server = server.SmartTCPServer(
4493
transport, host=host, port=port)
4494
note('listening on port: %s' % smart_server.port)
4497
def run(self, port=None, inet=False, directory=None, allow_writes=False):
4498
from bzrlib.transport import get_transport
4499
from bzrlib.transport.chroot import ChrootServer
4593
def run(self, port=None, inet=False, directory=None, allow_writes=False,
4595
from bzrlib.transport import get_transport, transport_server_registry
4500
4596
if directory is None:
4501
4597
directory = os.getcwd()
4598
if protocol is None:
4599
protocol = transport_server_registry.get()
4600
host, port = self.get_host_and_port(port)
4502
4601
url = urlutils.local_path_to_url(directory)
4503
4602
if not allow_writes:
4504
4603
url = 'readonly+' + url
4505
chroot_server = ChrootServer(get_transport(url))
4506
chroot_server.setUp()
4507
t = get_transport(chroot_server.get_url())
4508
smart_server = self.get_smart_server(t, inet, port)
4509
self.run_smart_server(smart_server)
4604
transport = get_transport(url)
4605
protocol(transport, host, port, inet)
4512
4608
class cmd_join(Command):
4513
"""Combine a subtree into its containing tree.
4609
"""Combine a tree into its containing tree.
4515
This command is for experimental use only. It requires the target tree
4516
to be in dirstate-with-subtree format, which cannot be converted into
4611
This command requires the target tree to be in a rich-root format.
4519
4613
The TREE argument should be an independent tree, inside another tree, but
4520
4614
not part of it. (Such trees can be produced by "bzr split", but also by
4769
4856
Option('body', help='Body for the email.', type=unicode),
4770
RegistryOption.from_kwargs('format',
4771
'Use the specified output format.',
4772
**{'4': 'Bundle format 4, Merge Directive 2 (default)',
4773
'0.9': 'Bundle format 0.9, Merge Directive 1',})
4857
RegistryOption('format',
4858
help='Use the specified output format.',
4859
lazy_registry=('bzrlib.send', 'format_registry'))
4776
4862
def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4777
4863
no_patch=False, revision=None, remember=False, output=None,
4778
format='4', mail_to=None, message=None, body=None, **kwargs):
4779
return self._run(submit_branch, revision, public_branch, remember,
4864
format=None, mail_to=None, message=None, body=None, **kwargs):
4865
from bzrlib.send import send
4866
return send(submit_branch, revision, public_branch, remember,
4780
4867
format, no_bundle, no_patch, output,
4781
kwargs.get('from', '.'), mail_to, message, body)
4783
def _run(self, submit_branch, revision, public_branch, remember, format,
4784
no_bundle, no_patch, output, from_, mail_to, message, body):
4785
from bzrlib.revision import NULL_REVISION
4786
branch = Branch.open_containing(from_)[0]
4788
outfile = cStringIO.StringIO()
4792
outfile = open(output, 'wb')
4793
# we may need to write data into branch's repository to calculate
4798
config = branch.get_config()
4800
mail_to = config.get_user_option('submit_to')
4801
mail_client = config.get_mail_client()
4802
if (not getattr(mail_client, 'supports_body', False)
4803
and body is not None):
4804
raise errors.BzrCommandError(
4805
'Mail client "%s" does not support specifying body' %
4806
mail_client.__class__.__name__)
4807
if remember and submit_branch is None:
4808
raise errors.BzrCommandError(
4809
'--remember requires a branch to be specified.')
4810
stored_submit_branch = branch.get_submit_branch()
4811
remembered_submit_branch = None
4812
if submit_branch is None:
4813
submit_branch = stored_submit_branch
4814
remembered_submit_branch = "submit"
4816
if stored_submit_branch is None or remember:
4817
branch.set_submit_branch(submit_branch)
4818
if submit_branch is None:
4819
submit_branch = branch.get_parent()
4820
remembered_submit_branch = "parent"
4821
if submit_branch is None:
4822
raise errors.BzrCommandError('No submit branch known or'
4824
if remembered_submit_branch is not None:
4825
note('Using saved %s location "%s" to determine what '
4826
'changes to submit.', remembered_submit_branch,
4830
submit_config = Branch.open(submit_branch).get_config()
4831
mail_to = submit_config.get_user_option("child_submit_to")
4833
stored_public_branch = branch.get_public_branch()
4834
if public_branch is None:
4835
public_branch = stored_public_branch
4836
elif stored_public_branch is None or remember:
4837
branch.set_public_branch(public_branch)
4838
if no_bundle and public_branch is None:
4839
raise errors.BzrCommandError('No public branch specified or'
4841
base_revision_id = None
4843
if revision is not None:
4844
if len(revision) > 2:
4845
raise errors.BzrCommandError('bzr send takes '
4846
'at most two one revision identifiers')
4847
revision_id = revision[-1].as_revision_id(branch)
4848
if len(revision) == 2:
4849
base_revision_id = revision[0].as_revision_id(branch)
4850
if revision_id is None:
4851
revision_id = branch.last_revision()
4852
if revision_id == NULL_REVISION:
4853
raise errors.BzrCommandError('No revisions to submit.')
4855
directive = merge_directive.MergeDirective2.from_objects(
4856
branch.repository, revision_id, time.time(),
4857
osutils.local_time_offset(), submit_branch,
4858
public_branch=public_branch, include_patch=not no_patch,
4859
include_bundle=not no_bundle, message=message,
4860
base_revision_id=base_revision_id)
4861
elif format == '0.9':
4864
patch_type = 'bundle'
4866
raise errors.BzrCommandError('Format 0.9 does not'
4867
' permit bundle with no patch')
4873
directive = merge_directive.MergeDirective.from_objects(
4874
branch.repository, revision_id, time.time(),
4875
osutils.local_time_offset(), submit_branch,
4876
public_branch=public_branch, patch_type=patch_type,
4879
outfile.writelines(directive.to_lines())
4881
subject = '[MERGE] '
4882
if message is not None:
4885
revision = branch.repository.get_revision(revision_id)
4886
subject += revision.get_summary()
4887
basename = directive.get_disk_name(branch)
4888
mail_client.compose_merge_request(mail_to, subject,
4868
kwargs.get('from', '.'), mail_to, message, body,
4897
4872
class cmd_bundle_revisions(cmd_send):
4899
4873
"""Create a merge-directive for submitting changes.
4901
4875
A merge directive provides many things needed for requesting merges:
5068
5043
graph = branch.repository.get_graph()
5069
5044
rev1, rev2 = _get_revision_range(revision, branch, self.name())
5070
5045
revid1, revid2 = rev1.rev_id, rev2.rev_id
5071
5046
# only show revisions between revid1 and revid2 (inclusive)
5072
5047
tags = [(tag, revid) for tag, revid in tags if
5073
5048
graph.is_between(revid, revid1, revid2)]
5078
elif sort == 'time':
5080
for tag, revid in tags:
5082
revobj = branch.repository.get_revision(revid)
5083
except errors.NoSuchRevision:
5084
timestamp = sys.maxint # place them at the end
5086
timestamp = revobj.timestamp
5087
timestamps[revid] = timestamp
5088
tags.sort(key=lambda x: timestamps[x[1]])
5090
# [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
5091
revno_map = branch.get_revision_id_to_revno_map()
5092
tags = [ (tag, '.'.join(map(str, revno_map.get(revid, ('?',)))))
5093
for tag, revid in tags ]
5051
elif sort == 'time':
5053
for tag, revid in tags:
5055
revobj = branch.repository.get_revision(revid)
5056
except errors.NoSuchRevision:
5057
timestamp = sys.maxint # place them at the end
5059
timestamp = revobj.timestamp
5060
timestamps[revid] = timestamp
5061
tags.sort(key=lambda x: timestamps[x[1]])
5063
# [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
5064
for index, (tag, revid) in enumerate(tags):
5066
revno = branch.revision_id_to_dotted_revno(revid)
5067
if isinstance(revno, tuple):
5068
revno = '.'.join(map(str, revno))
5069
except errors.NoSuchRevision:
5070
# Bad tag data/merges can lead to tagged revisions
5071
# which are not in this branch. Fail gracefully ...
5073
tags[index] = (tag, revno)
5094
5076
for tag, revspec in tags:
5095
5077
self.outf.write('%-20s %s\n' % (tag, revspec))
5195
5177
from bzrlib import switch
5196
5178
tree_location = '.'
5197
5179
control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
5198
branch = control_dir.open_branch()
5181
branch = control_dir.open_branch()
5182
had_explicit_nick = branch.get_config().has_explicit_nickname()
5183
except errors.NotBranchError:
5184
had_explicit_nick = False
5200
5186
to_branch = Branch.open(to_location)
5201
5187
except errors.NotBranchError:
5202
this_branch = control_dir.open_branch()
5203
# This may be a heavy checkout, where we want the master branch
5204
this_url = this_branch.get_bound_location()
5205
# If not, use a local sibling
5206
if this_url is None:
5207
this_url = this_branch.base
5188
this_url = self._get_branch_location(control_dir)
5208
5189
to_branch = Branch.open(
5209
5190
urlutils.join(this_url, '..', to_location))
5210
5191
switch.switch(control_dir, to_branch, force)
5211
if branch.get_config().has_explicit_nickname():
5192
if had_explicit_nick:
5212
5193
branch = control_dir.open_branch() #get the new branch!
5213
5194
branch.nick = to_branch.nick
5214
5195
note('Switched to branch: %s',
5215
5196
urlutils.unescape_for_display(to_branch.base, 'utf-8'))
5198
def _get_branch_location(self, control_dir):
5199
"""Return location of branch for this control dir."""
5201
this_branch = control_dir.open_branch()
5202
# This may be a heavy checkout, where we want the master branch
5203
master_location = this_branch.get_bound_location()
5204
if master_location is not None:
5205
return master_location
5206
# If not, use a local sibling
5207
return this_branch.base
5208
except errors.NotBranchError:
5209
format = control_dir.find_branch_format()
5210
if getattr(format, 'get_reference', None) is not None:
5211
return format.get_reference(control_dir)
5213
return control_dir.root_transport.base
5218
5216
class cmd_view(Command):
5219
5217
"""Manage filtered views.
5521
5519
dry_run=dry_run, no_prompt=force)
5524
def _create_prefix(cur_transport):
5525
needed = [cur_transport]
5526
# Recurse upwards until we can create a directory successfully
5528
new_transport = cur_transport.clone('..')
5529
if new_transport.base == cur_transport.base:
5530
raise errors.BzrCommandError(
5531
"Failed to create path prefix for %s."
5532
% cur_transport.base)
5534
new_transport.mkdir('.')
5535
except errors.NoSuchFile:
5536
needed.append(new_transport)
5537
cur_transport = new_transport
5522
class cmd_reference(Command):
5523
"""list, view and set branch locations for nested trees.
5525
If no arguments are provided, lists the branch locations for nested trees.
5526
If one argument is provided, display the branch location for that tree.
5527
If two arguments are provided, set the branch location for that tree.
5532
takes_args = ['path?', 'location?']
5534
def run(self, path=None, location=None):
5536
if path is not None:
5538
tree, branch, relpath =(
5539
bzrdir.BzrDir.open_containing_tree_or_branch(branchdir))
5540
if path is not None:
5543
tree = branch.basis_tree()
5545
info = branch._get_all_reference_info().iteritems()
5546
self._display_reference_info(tree, branch, info)
5540
# Now we only need to create child directories
5542
cur_transport = needed.pop()
5543
cur_transport.ensure_base()
5548
file_id = tree.path2id(path)
5550
raise errors.NotVersionedError(path)
5551
if location is None:
5552
info = [(file_id, branch.get_reference_info(file_id))]
5553
self._display_reference_info(tree, branch, info)
5555
branch.set_reference_info(file_id, path, location)
5557
def _display_reference_info(self, tree, branch, info):
5559
for file_id, (path, location) in info:
5561
path = tree.id2path(file_id)
5562
except errors.NoSuchId:
5564
ref_list.append((path, location))
5565
for path, location in sorted(ref_list):
5566
self.outf.write('%s %s\n' % (path, location))
5546
5569
# these get imported and then picked up by the scan for cmd_*