Merge lp:~mbp/bzr/715000-more-fallbacks into lp:bzr/2.2

Proposed by Martin Pool
Status: Superseded
Proposed branch: lp:~mbp/bzr/715000-more-fallbacks
Merge into: lp:bzr/2.2
Diff against target: 79168 lines (+36464/-22883)
520 files modified
.bzrignore (+2/-1)
.testr.conf (+2/-1)
Makefile (+13/-5)
NEWS (+2/-0)
README (+1/-1)
bzr (+1/-1)
bzrlib/__init__.py (+6/-6)
bzrlib/_btree_serializer_pyx.pyx (+545/-2)
bzrlib/_chk_map_pyx.pyx (+3/-2)
bzrlib/_dirstate_helpers_pyx.pyx (+36/-7)
bzrlib/_groupcompress_pyx.pyx (+20/-1)
bzrlib/_simple_set_pyx.pyx (+14/-0)
bzrlib/_static_tuple_c.pxd (+1/-0)
bzrlib/branch.py (+186/-64)
bzrlib/branchbuilder.py (+5/-1)
bzrlib/btree_index.py (+33/-16)
bzrlib/bugtracker.py (+22/-7)
bzrlib/builtins.py (+364/-204)
bzrlib/bundle/__init__.py (+5/-14)
bzrlib/bundle/bundle_data.py (+5/-6)
bzrlib/bundle/serializer/__init__.py (+6/-15)
bzrlib/bundle/serializer/v4.py (+42/-42)
bzrlib/bzrdir.py (+242/-975)
bzrlib/check.py (+6/-4)
bzrlib/chk_map.py (+1/-1)
bzrlib/clean_tree.py (+27/-5)
bzrlib/cmd_test_script.py (+65/-0)
bzrlib/cmd_version_info.py (+1/-1)
bzrlib/cmdline.py (+6/-2)
bzrlib/commands.py (+17/-5)
bzrlib/commit.py (+5/-5)
bzrlib/config.py (+579/-64)
bzrlib/conflicts.py (+49/-10)
bzrlib/controldir.py (+1009/-0)
bzrlib/crash.py (+7/-10)
bzrlib/delta.py (+9/-2)
bzrlib/diff-delta.c (+7/-5)
bzrlib/diff.py (+8/-8)
bzrlib/dirstate.py (+82/-16)
bzrlib/doc_generate/builders/__init__.py (+18/-0)
bzrlib/doc_generate/builders/texinfo.py (+42/-0)
bzrlib/doc_generate/conf.py (+6/-2)
bzrlib/doc_generate/writers/__init__.py (+18/-0)
bzrlib/doc_generate/writers/texinfo.py (+520/-0)
bzrlib/errors.py (+38/-11)
bzrlib/export/__init__.py (+5/-3)
bzrlib/fetch.py (+105/-31)
bzrlib/generate_ids.py (+1/-1)
bzrlib/graph.py (+272/-3)
bzrlib/groupcompress.py (+125/-48)
bzrlib/hashcache.py (+1/-1)
bzrlib/help_topics/__init__.py (+14/-9)
bzrlib/help_topics/en/configuration.txt (+41/-1)
bzrlib/help_topics/en/conflict-types.txt (+67/-37)
bzrlib/help_topics/en/debug-flags.txt (+1/-0)
bzrlib/hooks.py (+70/-51)
bzrlib/ignores.py (+2/-0)
bzrlib/inventory.py (+44/-151)
bzrlib/knit.py (+17/-16)
bzrlib/lazy_import.py (+4/-1)
bzrlib/lockdir.py (+14/-5)
bzrlib/log.py (+2/-2)
bzrlib/lru_cache.py (+1/-9)
bzrlib/lsprof.py (+15/-3)
bzrlib/merge.py (+29/-27)
bzrlib/mergetools.py (+116/-0)
bzrlib/msgeditor.py (+16/-16)
bzrlib/multiparent.py (+19/-8)
bzrlib/mutabletree.py (+8/-1)
bzrlib/option.py (+2/-2)
bzrlib/osutils.py (+111/-6)
bzrlib/plugin.py (+54/-3)
bzrlib/plugins/bash_completion/tests/test_bashcomp.py (+8/-7)
bzrlib/plugins/launchpad/__init__.py (+111/-3)
bzrlib/plugins/launchpad/lp_api.py (+49/-17)
bzrlib/plugins/launchpad/lp_directory.py (+61/-11)
bzrlib/plugins/launchpad/lp_propose.py (+12/-23)
bzrlib/plugins/launchpad/lp_registration.py (+1/-0)
bzrlib/plugins/launchpad/test_account.py (+2/-4)
bzrlib/plugins/launchpad/test_lp_api.py (+1/-2)
bzrlib/plugins/launchpad/test_lp_directory.py (+166/-9)
bzrlib/plugins/launchpad/test_lp_service.py (+2/-2)
bzrlib/plugins/launchpad/test_register.py (+24/-9)
bzrlib/progress.py (+0/-42)
bzrlib/push.py (+3/-2)
bzrlib/python-compat.h (+3/-0)
bzrlib/pyutils.py (+90/-0)
bzrlib/reconcile.py (+26/-9)
bzrlib/registry.py (+8/-17)
bzrlib/remote.py (+71/-24)
bzrlib/repofmt/groupcompress_repo.py (+153/-54)
bzrlib/repofmt/knitrepo.py (+69/-3)
bzrlib/repofmt/pack_repo.py (+34/-34)
bzrlib/repofmt/weaverepo.py (+129/-5)
bzrlib/repository.py (+197/-298)
bzrlib/revision.py (+0/-15)
bzrlib/revisionspec.py (+80/-6)
bzrlib/rules.py (+2/-3)
bzrlib/shelf.py (+4/-1)
bzrlib/shelf_ui.py (+7/-3)
bzrlib/smart/bzrdir.py (+5/-3)
bzrlib/smart/repository.py (+16/-4)
bzrlib/smart/server.py (+41/-20)
bzrlib/status.py (+110/-0)
bzrlib/store/text.py (+1/-1)
bzrlib/store/versioned/__init__.py (+3/-12)
bzrlib/strace.py (+23/-4)
bzrlib/symbol_versioning.py (+29/-11)
bzrlib/tag.py (+125/-16)
bzrlib/tests/EncodingAdapter.py (+1/-6)
bzrlib/tests/TestUtil.py (+17/-15)
bzrlib/tests/__init__.py (+419/-353)
bzrlib/tests/blackbox/__init__.py (+95/-89)
bzrlib/tests/blackbox/test_add.py (+24/-12)
bzrlib/tests/blackbox/test_alias.py (+11/-14)
bzrlib/tests/blackbox/test_aliases.py (+6/-13)
bzrlib/tests/blackbox/test_bound_branches.py (+3/-0)
bzrlib/tests/blackbox/test_branch.py (+60/-6)
bzrlib/tests/blackbox/test_break_lock.py (+56/-24)
bzrlib/tests/blackbox/test_cat_revision.py (+8/-0)
bzrlib/tests/blackbox/test_checkout.py (+14/-3)
bzrlib/tests/blackbox/test_commit.py (+5/-5)
bzrlib/tests/blackbox/test_config.py (+321/-0)
bzrlib/tests/blackbox/test_conflicts.py (+49/-141)
bzrlib/tests/blackbox/test_debug.py (+24/-5)
bzrlib/tests/blackbox/test_diff.py (+17/-3)
bzrlib/tests/blackbox/test_dpush.py (+11/-26)
bzrlib/tests/blackbox/test_exceptions.py (+14/-6)
bzrlib/tests/blackbox/test_filesystem_cicp.py (+4/-4)
bzrlib/tests/blackbox/test_filtered_view_ops.py (+2/-8)
bzrlib/tests/blackbox/test_help.py (+10/-8)
bzrlib/tests/blackbox/test_init.py (+20/-4)
bzrlib/tests/blackbox/test_locale.py (+5/-3)
bzrlib/tests/blackbox/test_merge.py (+21/-1)
bzrlib/tests/blackbox/test_mv.py (+9/-0)
bzrlib/tests/blackbox/test_non_ascii.py (+8/-8)
bzrlib/tests/blackbox/test_pull.py (+71/-0)
bzrlib/tests/blackbox/test_push.py (+26/-24)
bzrlib/tests/blackbox/test_remove.py (+32/-22)
bzrlib/tests/blackbox/test_repair_workingtree.py (+97/-0)
bzrlib/tests/blackbox/test_resolve.py (+93/-0)
bzrlib/tests/blackbox/test_script.py (+72/-0)
bzrlib/tests/blackbox/test_selftest.py (+11/-0)
bzrlib/tests/blackbox/test_send.py (+17/-25)
bzrlib/tests/blackbox/test_serve.py (+9/-12)
bzrlib/tests/blackbox/test_shared_repository.py (+3/-3)
bzrlib/tests/blackbox/test_shelve.py (+41/-0)
bzrlib/tests/blackbox/test_status.py (+58/-15)
bzrlib/tests/blackbox/test_tags.py (+103/-28)
bzrlib/tests/blackbox/test_too_much.py (+23/-32)
bzrlib/tests/blackbox/test_uncommit.py (+18/-1)
bzrlib/tests/blackbox/test_update.py (+38/-0)
bzrlib/tests/blackbox/test_upgrade.py (+79/-44)
bzrlib/tests/blackbox/test_version.py (+4/-4)
bzrlib/tests/blackbox/test_version_info.py (+17/-1)
bzrlib/tests/blackbox/test_view.py (+4/-11)
bzrlib/tests/blackbox/test_whoami.py (+9/-7)
bzrlib/tests/doc_generate/__init__.py (+113/-0)
bzrlib/tests/doc_generate/builders/__init__.py (+36/-0)
bzrlib/tests/doc_generate/builders/test_texinfo.py (+73/-0)
bzrlib/tests/doc_generate/writers/__init__.py (+36/-0)
bzrlib/tests/doc_generate/writers/test_texinfo.py (+338/-0)
bzrlib/tests/features.py (+11/-13)
bzrlib/tests/ftp_server/medusa_based.py (+6/-0)
bzrlib/tests/ftp_server/pyftpdlib_based.py (+7/-0)
bzrlib/tests/http_server.py (+58/-181)
bzrlib/tests/http_utils.py (+54/-25)
bzrlib/tests/https_server.py (+45/-15)
bzrlib/tests/per_branch/__init__.py (+4/-5)
bzrlib/tests/per_branch/test_bound_sftp.py (+1/-1)
bzrlib/tests/per_branch/test_branch.py (+8/-11)
bzrlib/tests/per_branch/test_commit.py (+1/-1)
bzrlib/tests/per_branch/test_last_revision_info.py (+24/-2)
bzrlib/tests/per_branch/test_locking.py (+0/-5)
bzrlib/tests/per_branch/test_parent.py (+2/-2)
bzrlib/tests/per_branch/test_pull.py (+51/-1)
bzrlib/tests/per_branch/test_push.py (+23/-7)
bzrlib/tests/per_branch/test_sprout.py (+22/-3)
bzrlib/tests/per_branch/test_stacking.py (+0/-2)
bzrlib/tests/per_branch/test_tags.py (+256/-3)
bzrlib/tests/per_branch/test_update.py (+23/-1)
bzrlib/tests/per_bzrdir/__init__.py (+91/-0)
bzrlib/tests/per_bzrdir/test_bzrdir.py (+492/-0)
bzrlib/tests/per_controldir/__init__.py (+13/-13)
bzrlib/tests/per_controldir/test_controldir.py (+162/-481)
bzrlib/tests/per_controldir/test_push.py (+7/-10)
bzrlib/tests/per_controldir_colo/__init__.py (+6/-6)
bzrlib/tests/per_controldir_colo/test_supported.py (+15/-18)
bzrlib/tests/per_controldir_colo/test_unsupported.py (+12/-15)
bzrlib/tests/per_interbranch/test_push.py (+5/-6)
bzrlib/tests/per_interrepository/__init__.py (+2/-8)
bzrlib/tests/per_interrepository/test_interrepository.py (+16/-17)
bzrlib/tests/per_intertree/__init__.py (+1/-2)
bzrlib/tests/per_lock/test_lock.py (+1/-1)
bzrlib/tests/per_merger.py (+1/-2)
bzrlib/tests/per_pack_repository.py (+4/-16)
bzrlib/tests/per_repository/__init__.py (+3/-3)
bzrlib/tests/per_repository/test_check.py (+2/-2)
bzrlib/tests/per_repository/test_commit_builder.py (+22/-8)
bzrlib/tests/per_repository/test_reconcile.py (+4/-5)
bzrlib/tests/per_repository/test_repository.py (+5/-11)
bzrlib/tests/per_repository/test_write_group.py (+30/-1)
bzrlib/tests/per_repository_chk/__init__.py (+2/-2)
bzrlib/tests/per_repository_reference/__init__.py (+4/-16)
bzrlib/tests/per_repository_reference/test_commit_with_stacking.py (+220/-0)
bzrlib/tests/per_repository_reference/test_fetch.py (+40/-1)
bzrlib/tests/per_transport.py (+34/-21)
bzrlib/tests/per_tree/__init__.py (+3/-8)
bzrlib/tests/per_uifactory/__init__.py (+25/-2)
bzrlib/tests/per_versionedfile.py (+103/-112)
bzrlib/tests/per_workingtree/__init__.py (+12/-9)
bzrlib/tests/per_workingtree/test_add_reference.py (+3/-7)
bzrlib/tests/per_workingtree/test_check_state.py (+110/-0)
bzrlib/tests/per_workingtree/test_commit.py (+5/-53)
bzrlib/tests/per_workingtree/test_merge_from_branch.py (+0/-8)
bzrlib/tests/per_workingtree/test_move.py (+23/-37)
bzrlib/tests/per_workingtree/test_pull.py (+44/-10)
bzrlib/tests/per_workingtree/test_remove.py (+51/-58)
bzrlib/tests/per_workingtree/test_rename_one.py (+43/-0)
bzrlib/tests/per_workingtree/test_smart_add.py (+36/-6)
bzrlib/tests/per_workingtree/test_symlinks.py (+1/-1)
bzrlib/tests/per_workingtree/test_unversion.py (+2/-2)
bzrlib/tests/per_workingtree/test_workingtree.py (+27/-11)
bzrlib/tests/scenarios.py (+61/-0)
bzrlib/tests/script.py (+66/-22)
bzrlib/tests/stub_sftp.py (+144/-142)
bzrlib/tests/test__annotator.py (+1/-2)
bzrlib/tests/test__bencode.py (+10/-1)
bzrlib/tests/test__btree_serializer.py (+305/-0)
bzrlib/tests/test__chk_map.py (+1/-2)
bzrlib/tests/test__dirstate_helpers.py (+33/-52)
bzrlib/tests/test__groupcompress.py (+27/-19)
bzrlib/tests/test__known_graph.py (+21/-26)
bzrlib/tests/test__simple_set.py (+11/-3)
bzrlib/tests/test__static_tuple.py (+1/-3)
bzrlib/tests/test_ancestry.py (+1/-6)
bzrlib/tests/test_annotate.py (+1/-4)
bzrlib/tests/test_bad_files.py (+1/-2)
bzrlib/tests/test_bisect_multi.py (+1/-2)
bzrlib/tests/test_branch.py (+45/-24)
bzrlib/tests/test_branchbuilder.py (+16/-2)
bzrlib/tests/test_btree_index.py (+29/-29)
bzrlib/tests/test_bugtracker.py (+28/-6)
bzrlib/tests/test_bundle.py (+3/-6)
bzrlib/tests/test_bzrdir.py (+112/-61)
bzrlib/tests/test_chk_map.py (+0/-2)
bzrlib/tests/test_chk_serializer.py (+1/-8)
bzrlib/tests/test_clean_tree.py (+63/-2)
bzrlib/tests/test_cmdline.py (+0/-1)
bzrlib/tests/test_commands.py (+2/-5)
bzrlib/tests/test_commit.py (+2/-6)
bzrlib/tests/test_commit_merge.py (+2/-5)
bzrlib/tests/test_config.py (+576/-155)
bzrlib/tests/test_conflicts.py (+209/-207)
bzrlib/tests/test_crash.py (+11/-3)
bzrlib/tests/test_debug.py (+9/-34)
bzrlib/tests/test_delta.py (+15/-2)
bzrlib/tests/test_diff.py (+13/-22)
bzrlib/tests/test_dirstate.py (+60/-19)
bzrlib/tests/test_eol_filters.py (+1/-2)
bzrlib/tests/test_errors.py (+6/-3)
bzrlib/tests/test_extract.py (+1/-2)
bzrlib/tests/test_fetch.py (+1/-10)
bzrlib/tests/test_foreign.py (+21/-12)
bzrlib/tests/test_ftp_transport.py (+1/-3)
bzrlib/tests/test_generate_docs.py (+2/-2)
bzrlib/tests/test_generate_ids.py (+1/-3)
bzrlib/tests/test_globbing.py (+7/-6)
bzrlib/tests/test_gpg.py (+2/-3)
bzrlib/tests/test_graph.py (+64/-2)
bzrlib/tests/test_groupcompress.py (+59/-11)
bzrlib/tests/test_hashcache.py (+5/-3)
bzrlib/tests/test_help.py (+1/-3)
bzrlib/tests/test_hooks.py (+15/-2)
bzrlib/tests/test_http.py (+409/-434)
bzrlib/tests/test_https_ca_bundle.py (+6/-18)
bzrlib/tests/test_ignores.py (+10/-3)
bzrlib/tests/test_import_tariff.py (+18/-8)
bzrlib/tests/test_index.py (+1/-1)
bzrlib/tests/test_info.py (+1/-2)
bzrlib/tests/test_inv.py (+28/-24)
bzrlib/tests/test_inventory_delta.py (+5/-5)
bzrlib/tests/test_knit.py (+3/-3)
bzrlib/tests/test_lazy_import.py (+35/-10)
bzrlib/tests/test_library_state.py (+1/-2)
bzrlib/tests/test_lock.py (+11/-14)
bzrlib/tests/test_lockable_files.py (+1/-7)
bzrlib/tests/test_lockdir.py (+11/-14)
bzrlib/tests/test_lru_cache.py (+0/-7)
bzrlib/tests/test_lsprof.py (+1/-2)
bzrlib/tests/test_merge.py (+20/-0)
bzrlib/tests/test_merge3.py (+1/-3)
bzrlib/tests/test_merge_core.py (+6/-3)
bzrlib/tests/test_mergetools.py (+167/-0)
bzrlib/tests/test_missing.py (+1/-5)
bzrlib/tests/test_msgeditor.py (+66/-76)
bzrlib/tests/test_multiparent.py (+1/-2)
bzrlib/tests/test_nonascii.py (+1/-2)
bzrlib/tests/test_options.py (+25/-16)
bzrlib/tests/test_osutils.py (+80/-24)
bzrlib/tests/test_osutils_encodings.py (+4/-7)
bzrlib/tests/test_permissions.py (+4/-6)
bzrlib/tests/test_plugins.py (+58/-21)
bzrlib/tests/test_progress.py (+1/-6)
bzrlib/tests/test_pyutils.py (+88/-0)
bzrlib/tests/test_read_bundle.py (+10/-36)
bzrlib/tests/test_reconcile.py (+1/-3)
bzrlib/tests/test_registry.py (+9/-2)
bzrlib/tests/test_remote.py (+84/-32)
bzrlib/tests/test_repository.py (+23/-10)
bzrlib/tests/test_revision.py (+2/-34)
bzrlib/tests/test_revisionspec.py (+78/-7)
bzrlib/tests/test_revisiontree.py (+1/-3)
bzrlib/tests/test_rio.py (+9/-7)
bzrlib/tests/test_rules.py (+4/-7)
bzrlib/tests/test_scenarios.py (+110/-0)
bzrlib/tests/test_script.py (+135/-5)
bzrlib/tests/test_selftest.py (+581/-45)
bzrlib/tests/test_server.py (+510/-19)
bzrlib/tests/test_setup.py (+18/-14)
bzrlib/tests/test_sftp_transport.py (+13/-24)
bzrlib/tests/test_shelf.py (+24/-1)
bzrlib/tests/test_smart.py (+66/-6)
bzrlib/tests/test_smart_request.py (+5/-3)
bzrlib/tests/test_smart_transport.py (+52/-45)
bzrlib/tests/test_smtp_connection.py (+8/-10)
bzrlib/tests/test_source.py (+15/-6)
bzrlib/tests/test_ssh_transport.py (+31/-2)
bzrlib/tests/test_status.py (+69/-2)
bzrlib/tests/test_store.py (+19/-18)
bzrlib/tests/test_strace.py (+28/-27)
bzrlib/tests/test_subsume.py (+2/-2)
bzrlib/tests/test_switch.py (+2/-2)
bzrlib/tests/test_symbol_versioning.py (+1/-2)
bzrlib/tests/test_tag.py (+5/-2)
bzrlib/tests/test_test_server.py (+260/-0)
bzrlib/tests/test_testament.py (+2/-2)
bzrlib/tests/test_timestamp.py (+42/-1)
bzrlib/tests/test_trace.py (+15/-5)
bzrlib/tests/test_transactions.py (+2/-6)
bzrlib/tests/test_transform.py (+176/-45)
bzrlib/tests/test_transport.py (+19/-4)
bzrlib/tests/test_transport_log.py (+1/-3)
bzrlib/tests/test_tree.py (+1/-2)
bzrlib/tests/test_tuned_gzip.py (+27/-9)
bzrlib/tests/test_ui.py (+78/-28)
bzrlib/tests/test_upgrade.py (+130/-53)
bzrlib/tests/test_upgrade_stacked.py (+24/-23)
bzrlib/tests/test_urlutils.py (+2/-0)
bzrlib/tests/test_version.py (+1/-2)
bzrlib/tests/test_version_info.py (+2/-2)
bzrlib/tests/test_versionedfile.py (+139/-0)
bzrlib/tests/test_weave.py (+9/-2)
bzrlib/tests/test_whitebox.py (+2/-4)
bzrlib/tests/test_win32utils.py (+7/-6)
bzrlib/tests/test_workingtree.py (+30/-4)
bzrlib/tests/test_wsgi.py (+2/-2)
bzrlib/tests/test_xml.py (+2/-3)
bzrlib/tests/testui.py (+46/-0)
bzrlib/tests/transport_util.py (+2/-2)
bzrlib/timestamp.py (+1/-29)
bzrlib/trace.py (+26/-4)
bzrlib/transform.py (+274/-134)
bzrlib/transport/__init__.py (+13/-0)
bzrlib/transport/ftp/__init__.py (+25/-6)
bzrlib/transport/ftp/_gssapi.py (+1/-1)
bzrlib/transport/gio_transport.py (+17/-1)
bzrlib/transport/http/__init__.py (+19/-3)
bzrlib/transport/http/_pycurl.py (+26/-6)
bzrlib/transport/http/_urllib.py (+5/-0)
bzrlib/transport/http/_urllib2_wrappers.py (+79/-21)
bzrlib/transport/local.py (+4/-1)
bzrlib/transport/pathfilter.py (+0/-1)
bzrlib/transport/remote.py (+3/-1)
bzrlib/transport/sftp.py (+7/-0)
bzrlib/transport/ssh.py (+32/-22)
bzrlib/tree.py (+1/-1)
bzrlib/tuned_gzip.py (+17/-2)
bzrlib/ui/__init__.py (+68/-1)
bzrlib/upgrade.py (+228/-16)
bzrlib/urlutils.py (+3/-2)
bzrlib/version_info_formats/__init__.py (+0/-3)
bzrlib/version_info_formats/format_python.py (+1/-2)
bzrlib/versionedfile.py (+187/-46)
bzrlib/weavefile.py (+1/-1)
bzrlib/workingtree.py (+184/-78)
bzrlib/workingtree_4.py (+22/-3)
bzrlib/xml_serializer.py (+2/-67)
contrib/add-bzr-to-baz (+0/-16)
contrib/newinventory.py (+0/-144)
contrib/pwclient.full (+0/-643)
contrib/pwk (+0/-50)
doc/developers/HACKING.txt (+1/-265)
doc/developers/authentication-ring.txt (+11/-11)
doc/developers/bug-handling.txt (+1/-1)
doc/developers/check.txt (+1/-1)
doc/developers/code-review.txt (+3/-3)
doc/developers/code-style.txt (+58/-3)
doc/developers/conf.py (+1/-1)
doc/developers/contribution-quickstart.txt (+1/-1)
doc/developers/cycle.txt (+26/-28)
doc/developers/directory-fingerprints.txt (+1/-1)
doc/developers/documenting-changes.txt (+100/-0)
doc/developers/ec2.txt (+1/-1)
doc/developers/fetch.txt (+86/-0)
doc/developers/groupcompress-design.txt (+1/-1)
doc/developers/incremental-push-pull.txt (+3/-3)
doc/developers/index-plain.txt (+8/-0)
doc/developers/index.txt (+11/-0)
doc/developers/initial-push-pull.txt (+1/-1)
doc/developers/integration.txt (+28/-3)
doc/developers/inventory.txt (+5/-5)
doc/developers/network-protocol.txt (+7/-7)
doc/developers/overview.txt (+223/-60)
doc/developers/packrepo.txt (+1/-1)
doc/developers/performance-roadmap-rationale.txt (+1/-1)
doc/developers/performance-use-case-analysis.txt (+4/-4)
doc/developers/planned-change-integration.txt (+4/-4)
doc/developers/planned-performance-changes.txt (+4/-4)
doc/developers/ppa.txt (+143/-67)
doc/developers/releasing.txt (+176/-49)
doc/developers/repository.txt (+1/-1)
doc/developers/revert.txt (+1/-1)
doc/developers/testing.txt (+231/-20)
doc/developers/tortoise-strategy.txt (+2/-2)
doc/developers/transports.txt (+108/-0)
doc/developers/ui.txt (+235/-0)
doc/developers/win32_build_setup.txt (+1/-1)
doc/developers/xdg_config_spec.txt (+27/-0)
doc/en/Makefile (+4/-0)
doc/en/_templates/index.html (+1/-1)
doc/en/admin-guide/other-setups.txt (+10/-10)
doc/en/conf.py (+5/-3)
doc/en/index.txt (+1/-1)
doc/en/mini-tutorial/index.txt (+4/-4)
doc/en/release-notes/bzr-0.1.txt (+753/-0)
doc/en/release-notes/bzr-0.10.txt (+90/-0)
doc/en/release-notes/bzr-0.11.txt (+226/-0)
doc/en/release-notes/bzr-0.12.txt (+146/-0)
doc/en/release-notes/bzr-0.13.txt (+145/-0)
doc/en/release-notes/bzr-0.14.txt (+168/-0)
doc/en/release-notes/bzr-0.15.txt (+391/-0)
doc/en/release-notes/bzr-0.16.txt (+379/-0)
doc/en/release-notes/bzr-0.17.txt (+129/-0)
doc/en/release-notes/bzr-0.18.txt (+274/-0)
doc/en/release-notes/bzr-0.6.txt (+227/-0)
doc/en/release-notes/bzr-0.7.txt (+308/-0)
doc/en/release-notes/bzr-0.8.txt (+340/-0)
doc/en/release-notes/bzr-0.9.txt (+280/-0)
doc/en/release-notes/bzr-0.90.txt (+311/-0)
doc/en/release-notes/bzr-0.91.txt (+372/-0)
doc/en/release-notes/bzr-0.92.txt (+342/-0)
doc/en/release-notes/bzr-1.0.txt (+429/-0)
doc/en/release-notes/bzr-1.1.txt (+228/-0)
doc/en/release-notes/bzr-1.10.txt (+160/-0)
doc/en/release-notes/bzr-1.11.txt (+278/-0)
doc/en/release-notes/bzr-1.12.txt (+227/-0)
doc/en/release-notes/bzr-1.13.txt (+400/-0)
doc/en/release-notes/bzr-1.14.txt (+459/-0)
doc/en/release-notes/bzr-1.15.txt (+230/-0)
doc/en/release-notes/bzr-1.16.txt (+269/-0)
doc/en/release-notes/bzr-1.17.txt (+259/-0)
doc/en/release-notes/bzr-1.18.txt (+393/-0)
doc/en/release-notes/bzr-1.2.txt (+224/-0)
doc/en/release-notes/bzr-1.3.txt (+239/-0)
doc/en/release-notes/bzr-1.4.txt (+347/-0)
doc/en/release-notes/bzr-1.5.txt (+206/-0)
doc/en/release-notes/bzr-1.6.txt (+818/-0)
doc/en/release-notes/bzr-1.7.txt (+282/-0)
doc/en/release-notes/bzr-1.8.txt (+234/-0)
doc/en/release-notes/bzr-1.9.txt (+154/-0)
doc/en/release-notes/bzr-2.0.txt (+648/-0)
doc/en/release-notes/bzr-2.1.txt (+1244/-0)
doc/en/release-notes/bzr-2.2.txt (+1342/-0)
doc/en/release-notes/bzr-2.3.txt (+870/-13420)
doc/en/release-notes/bzr-2.4.txt (+126/-0)
doc/en/release-notes/release-template.txt (+26/-4)
doc/en/release-notes/series-template.txt (+62/-0)
doc/en/tutorials/tutorial.txt (+3/-3)
doc/en/tutorials/using_bazaar_with_launchpad.txt (+35/-0)
doc/en/upgrade-guide/data_migration.txt (+10/-6)
doc/en/upgrade-guide/index.txt (+3/-3)
doc/en/upgrade-guide/overview.txt (+15/-20)
doc/en/user-guide/branching_a_project.txt (+8/-2)
doc/en/user-guide/configuring_bazaar.txt (+68/-1)
doc/en/user-guide/hooks.txt (+1/-1)
doc/en/user-guide/http_smart_server.txt (+7/-9)
doc/en/user-guide/organizing_your_workspace.txt (+1/-1)
doc/en/user-guide/server.txt (+1/-1)
doc/en/user-guide/shared_repository_layouts.txt (+1/-1)
doc/en/user-guide/specifying_revisions.txt (+1/-1)
doc/en/whats-new/whats-new-in-2.2.txt (+1/-1)
doc/en/whats-new/whats-new-in-2.3.txt (+193/-0)
doc/en/whats-new/whats-new-in-2.4.txt (+48/-0)
doc/es/conf.py (+1/-1)
doc/es/mini-tutorial/index.txt (+2/-2)
doc/ja/conf.py (+1/-1)
doc/ja/user-guide/http_smart_server.txt (+3/-3)
doc/ja/user-reference/index.txt (+1/-1)
doc/ru/conf.py (+1/-1)
doc/ru/tutorials/tutorial.txt (+1/-1)
doc/ru/user-guide/branching_a_project.txt (+1/-1)
setup.py (+4/-15)
tools/check-newsbugs.py (+39/-7)
tools/convertfile.py (+0/-87)
tools/convertinv.py (+0/-75)
tools/fixed-in.py (+172/-0)
tools/generate_release_notes.py (+103/-52)
tools/packaging/build-packages.sh (+1/-1)
tools/packaging/update-changelogs.sh (+2/-1)
tools/packaging/update-control.sh (+1/-0)
tools/packaging/update-packaging-branches.sh (+1/-4)
tools/trace-revisions (+0/-19)
tools/weavebench.py (+0/-106)
tools/win32/bazaar.url (+1/-1)
tools/win32/build_release.py (+0/-1)
tools/win32/buildout.cfg (+1/-1)
tools/win32/bzr.iss.cog (+4/-4)
tools/win32/bzr_postinstall.py (+3/-0)
tools/win32/start_bzr.bat (+3/-4)
To merge this branch: bzr merge lp:~mbp/bzr/715000-more-fallbacks
Reviewer Review Type Date Requested Status
John A Meinel Needs Information
Review via email: mp+49026@code.launchpad.net

This proposal supersedes a proposal from 2011-02-09.

This proposal has been superseded by a proposal from 2011-02-09.

Description of the change

follow-through from bug 715000: rename _fallback_vfs to _immediate_fallbacks to make it clear it's not the whole stack.

To post a comment you must log in.
Revision history for this message
John A Meinel (jameinel) wrote : Posted in a previous version of this proposal

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 2/9/2011 2:08 AM, Martin Pool wrote:
> Martin Pool has proposed merging lp:~mbp/bzr/715000-more-fallbacks into lp:bzr.
>
> Requested reviews:
> bzr-core (bzr-core)
>
> For more details, see:
> https://code.launchpad.net/~mbp/bzr/715000-more-fallbacks/+merge/49025
>
> follow-through from bug 715000: rename _fallback_vfs to _immediate_fallbacks to make it clear it's not the whole stack.

I'm ok with the change, but I would make it "_immediate_fallback_vfs" to
distinguish it from "_immediate_fallback_repositories".
Mostly to be easily greppable.

I don't personally find it better, mostly because the added length
doesn't add much. It seems a simple

  :ivar _fallback_vfs: Immediate fallbacks, note this is not transitive

Could be a better way to go.

John
=:->
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk1St0oACgkQJdeBCYSNAAOLHQCg0Yj/BsMKAzL4Sr5OhGQbxBoZ
9FMAnj/yOfdMjxhNnjLFiYvdnY9+ansx
=LcsQ
-----END PGP SIGNATURE-----

Revision history for this message
John A Meinel (jameinel) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 2/9/2011 2:09 AM, Martin Pool wrote:
> Martin Pool has proposed merging lp:~mbp/bzr/715000-more-fallbacks into lp:bzr/2.2.
>
> Requested reviews:
> bzr-core (bzr-core)
>
> For more details, see:
> https://code.launchpad.net/~mbp/bzr/715000-more-fallbacks/+merge/49026
>
> follow-through from bug 715000: rename _fallback_vfs to _immediate_fallbacks to make it clear it's not the whole stack.

I don't really like changing the name of things in a stable series. Do
you feel this is really necessary?

 review: needs_information

John
=:->

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk1St2gACgkQJdeBCYSNAAPIYwCeJ4s9T48rbxRduTts3rarhkPu
1UMAoKDzNFENu713ShbJuPiCF9zDJQdi
=F4wU
-----END PGP SIGNATURE-----

review: Needs Information

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2010-04-01 04:41:18 +0000
3+++ .bzrignore 2011-02-09 08:08:20 +0000
4@@ -19,7 +19,8 @@
5 ./doc/**/*.html
6 ./doc/developers/performance.png
7 ./doc/en/user-reference/*.txt
8-./doc/en/release-notes/*.txt
9+./doc/en/release-notes/index.txt
10+./doc/en/release-notes/NEWS.txt
11 BRANCH-INFO
12 # setup.py working directory
13 ./build
14
15=== modified file '.testr.conf'
16--- .testr.conf 2010-02-28 10:08:29 +0000
17+++ .testr.conf 2011-02-09 08:08:20 +0000
18@@ -1,3 +1,4 @@
19 [DEFAULT]
20-test_command=./bzr selftest --subunit $IDOPTION
21+test_command=./bzr selftest --subunit $IDOPTION $LISTOPT
22 test_id_option=--load-list $IDFILE
23+test_list_option=--list
24
25=== modified file 'Makefile'
26--- Makefile 2010-04-06 06:59:03 +0000
27+++ Makefile 2011-02-09 08:08:20 +0000
28@@ -39,8 +39,14 @@
29 check: docs check-nodocs
30
31 check-nodocs: extensions
32+ set -e
33 # Generate a stream for PQM to watch.
34+ -$(RM) -f selftest.log
35 $(PYTHON) -Werror -O ./bzr selftest --subunit $(tests) | tee selftest.log
36+ # An empty log file should catch errors in the $(PYTHON)
37+ # command above (the '|' swallow any errors since 'make'
38+ # sees the 'tee' exit code for the whole line
39+ if [ ! -s selftest.log ] ; then exit 1 ; fi
40 # Check that there were no errors reported.
41 subunit-stats < selftest.log
42
43@@ -133,11 +139,13 @@
44 doc/developers/Makefile \
45 doc/developers/make.bat
46
47+NEWS_FILES = $(wildcard doc/en/release-notes/bzr-*.txt)
48+
49 doc/en/user-reference/index.txt: $(MAN_DEPENDENCIES)
50 $(PYTHON) tools/generate_docs.py -o $@ rstx
51
52-doc/en/release-notes/index.txt: NEWS tools/generate_release_notes.py
53- $(PYTHON) tools/generate_release_notes.py NEWS $@
54+doc/en/release-notes/index.txt: $(NEWS_FILES) tools/generate_release_notes.py
55+ $(PYTHON) tools/generate_release_notes.py $@ $(NEWS_FILES)
56
57 doc/%/Makefile: doc/en/Makefile
58 $(PYTHON) -c "import shutil; shutil.copyfile('$<', '$@')"
59@@ -296,10 +304,10 @@
60 $(rst2html) --stylesheet=default.css $< $@
61
62 %.html: %.txt
63- $(rst2html) --stylesheet=../../default.css $< $@
64+ $(rst2html) --stylesheet=../../default.css $< "$@"
65
66-doc/en/release-notes/NEWS.txt: NEWS
67- $(PYTHON) -c "import shutil; shutil.copyfile('$<', '$@')"
68+doc/en/release-notes/NEWS.txt: $(NEWS_FILES) tools/generate_release_notes.py
69+ $(PYTHON) tools/generate_release_notes.py "$@" $(NEWS_FILES)
70
71 upgrade_guide_dependencies = $(wildcard $(addsuffix /*.txt, doc/en/upgrade-guide))
72
73
74=== added file 'NEWS'
75--- NEWS 1970-01-01 00:00:00 +0000
76+++ NEWS 2011-02-09 08:08:20 +0000
77@@ -0,0 +1,2 @@
78+The NEWS file has been moved and split into multiple files (one per release
79+series). The NEWS files are now found in doc/en/release-notes/.
80
81=== modified file 'README'
82--- README 2010-01-29 14:09:05 +0000
83+++ README 2011-02-09 08:08:20 +0000
84@@ -36,7 +36,7 @@
85 It also directly supports and encourages a large number of development best
86 practices like refactoring and pre-commit regression testing. Users can
87 choose between our command line tool and our cross-platform GUI application.
88-For further details, see our website at http://bazaar-vcs.org/en.
89+For further details, see our website at http://bazaar.canonical.com/en/
90
91 Feedback
92 ========
93
94=== modified file 'bzr'
95--- bzr 2011-02-04 14:04:18 +0000
96+++ bzr 2011-02-09 08:08:20 +0000
97@@ -23,7 +23,7 @@
98 import warnings
99
100 # update this on each release
101-_script_version = (2, 2, 5)
102+_script_version = (2, 4, 0)
103
104 try:
105 version_info = sys.version_info
106
107=== modified file 'bzrlib/__init__.py'
108--- bzrlib/__init__.py 2011-02-04 14:04:18 +0000
109+++ bzrlib/__init__.py 2011-02-09 08:08:20 +0000
110@@ -1,4 +1,4 @@
111-# Copyright (C) 2005-2010 Canonical Ltd
112+# Copyright (C) 2005-2011 Canonical Ltd
113 #
114 # This program is free software; you can redistribute it and/or modify
115 # it under the terms of the GNU General Public License as published by
116@@ -52,10 +52,10 @@
117 # Python version 2.0 is (2, 0, 0, 'final', 0)." Additionally we use a
118 # releaselevel of 'dev' for unreleased under-development code.
119
120-version_info = (2, 2, 5, 'dev', 0)
121+version_info = (2, 4, 0, 'dev', 1)
122
123 # API compatibility version
124-api_minimum_version = (2, 2, 0)
125+api_minimum_version = (2, 4, 0)
126
127
128 def _format_version_tuple(version_info):
129@@ -71,17 +71,17 @@
130 1.0.0
131 >>> print _format_version_tuple((1, 2, 0, 'dev', 0))
132 1.2.0dev
133- >>> print bzrlib._format_version_tuple((1, 2, 0, 'dev', 1))
134+ >>> print _format_version_tuple((1, 2, 0, 'dev', 1))
135 1.2.0dev1
136 >>> print _format_version_tuple((1, 1, 1, 'candidate', 2))
137 1.1.1rc2
138- >>> print bzrlib._format_version_tuple((2, 1, 0, 'beta', 1))
139+ >>> print _format_version_tuple((2, 1, 0, 'beta', 1))
140 2.1b1
141 >>> print _format_version_tuple((1, 4, 0))
142 1.4.0
143 >>> print _format_version_tuple((1, 4))
144 1.4
145- >>> print bzrlib._format_version_tuple((2, 1, 0, 'final', 1))
146+ >>> print _format_version_tuple((2, 1, 0, 'final', 1))
147 Traceback (most recent call last):
148 ...
149 ValueError: version_info (2, 1, 0, 'final', 1) not valid
150
151=== modified file 'bzrlib/_btree_serializer_pyx.pyx'
152--- bzrlib/_btree_serializer_pyx.pyx 2010-02-17 17:11:16 +0000
153+++ bzrlib/_btree_serializer_pyx.pyx 2011-02-09 08:08:20 +0000
154@@ -33,6 +33,7 @@
155 char *PyString_AsString(object p) except NULL
156 object PyString_FromStringAndSize(char *, Py_ssize_t)
157 PyObject *PyString_FromStringAndSize_ptr "PyString_FromStringAndSize" (char *, Py_ssize_t)
158+ object PyString_FromFormat(char *, ...)
159 int PyString_CheckExact(object s)
160 int PyString_CheckExact_ptr "PyString_CheckExact" (PyObject *)
161 Py_ssize_t PyString_Size(object p)
162@@ -49,19 +50,31 @@
163 PyObject *PyTuple_GET_ITEM_ptr_object "PyTuple_GET_ITEM" (object tpl, int index)
164 void Py_INCREF(object)
165 void Py_DECREF_ptr "Py_DECREF" (PyObject *)
166+ void *PyMem_Malloc(size_t nbytes)
167+ void PyMem_Free(void *)
168+ void memset(void *, int, size_t)
169
170 cdef extern from "string.h":
171 void *memcpy(void *dest, void *src, size_t n)
172 void *memchr(void *s, int c, size_t n)
173+ int memcmp(void *s1, void *s2, size_t n)
174 # GNU extension
175 # void *memrchr(void *s, int c, size_t n)
176 int strncmp(char *s1, char *s2, size_t n)
177+ unsigned long strtoul(char *s1, char **out, int base)
178+ long long strtoll(char *s1, char **out, int base)
179+
180
181 # It seems we need to import the definitions so that the pyrex compiler has
182 # local names to access them.
183 from _static_tuple_c cimport StaticTuple, \
184 import_static_tuple_c, StaticTuple_New, \
185- StaticTuple_Intern, StaticTuple_SET_ITEM, StaticTuple_CheckExact
186+ StaticTuple_Intern, StaticTuple_SET_ITEM, StaticTuple_CheckExact, \
187+ StaticTuple_GET_SIZE, StaticTuple_GET_ITEM
188+# This tells the test infrastructure that StaticTuple is a class, so we don't
189+# have to worry about exception checking.
190+## extern cdef class StaticTuple
191+import sys
192
193
194 # TODO: Find some way to import this from _dirstate_helpers
195@@ -103,7 +116,6 @@
196 Py_DECREF_ptr(py_str)
197 return result
198
199-from bzrlib import _static_tuple_c
200 # This sets up the StaticTuple C_API functionality
201 import_static_tuple_c()
202
203@@ -315,6 +327,537 @@
204 return parser.parse()
205
206
207+# TODO: We can go from 8 byte offset + 4 byte length to a simple lookup,
208+# because the block_offset + length is likely to be repeated. However,
209+# the big win there is to cache across pages, and not just one page
210+# Though if we did cache in a page, we could certainly use a short int.
211+# And this goes from 40 bytes to 30 bytes.
212+# One slightly ugly option would be to cache block offsets in a global.
213+# However, that leads to thread-safety issues, etc.
214+ctypedef struct gc_chk_sha1_record:
215+ long long block_offset
216+ unsigned int block_length
217+ unsigned int record_start
218+ unsigned int record_end
219+ char sha1[20]
220+
221+
222+cdef int _unhexbuf[256]
223+cdef char *_hexbuf
224+_hexbuf = '0123456789abcdef'
225+
226+cdef _populate_unhexbuf():
227+ cdef int i
228+ for i from 0 <= i < 256:
229+ _unhexbuf[i] = -1
230+ for i from 0 <= i < 10: # 0123456789 => map to the raw number
231+ _unhexbuf[(i + c'0')] = i
232+ for i from 10 <= i < 16: # abcdef => 10, 11, 12, 13, 14, 15, 16
233+ _unhexbuf[(i - 10 + c'a')] = i
234+ for i from 10 <= i < 16: # ABCDEF => 10, 11, 12, 13, 14, 15, 16
235+ _unhexbuf[(i - 10 + c'A')] = i
236+_populate_unhexbuf()
237+
238+
239+cdef int _unhexlify_sha1(char *as_hex, char *as_bin): # cannot_raise
240+ """Take the hex sha1 in as_hex and make it binary in as_bin
241+
242+ Same as binascii.unhexlify, but working on C strings, not Python objects.
243+ """
244+ cdef int top
245+ cdef int bot
246+ cdef int i, j
247+ cdef char *cur
248+
249+ # binascii does this using isupper() and tolower() and ?: syntax. I'm
250+ # guessing a simple lookup array should be faster.
251+ j = 0
252+ for i from 0 <= i < 20:
253+ top = _unhexbuf[<unsigned char>(as_hex[j])]
254+ j = j + 1
255+ bot = _unhexbuf[<unsigned char>(as_hex[j])]
256+ j = j + 1
257+ if top == -1 or bot == -1:
258+ return 0
259+ as_bin[i] = <unsigned char>((top << 4) + bot);
260+ return 1
261+
262+
263+def _py_unhexlify(as_hex):
264+ """For the test infrastructure, just thunks to _unhexlify_sha1"""
265+ if len(as_hex) != 40 or not PyString_CheckExact(as_hex):
266+ raise ValueError('not a 40-byte hex digest')
267+ as_bin = PyString_FromStringAndSize(NULL, 20)
268+ if _unhexlify_sha1(PyString_AS_STRING(as_hex), PyString_AS_STRING(as_bin)):
269+ return as_bin
270+ return None
271+
272+
273+cdef void _hexlify_sha1(char *as_bin, char *as_hex): # cannot_raise
274+ cdef int i, j
275+ cdef char c
276+
277+ j = 0
278+ for i from 0 <= i < 20:
279+ c = as_bin[i]
280+ as_hex[j] = _hexbuf[(c>>4)&0xf]
281+ j = j + 1
282+ as_hex[j] = _hexbuf[(c)&0xf]
283+ j = j + 1
284+
285+
286+def _py_hexlify(as_bin):
287+ """For test infrastructure, thunk to _hexlify_sha1"""
288+ if len(as_bin) != 20 or not PyString_CheckExact(as_bin):
289+ raise ValueError('not a 20-byte binary digest')
290+ as_hex = PyString_FromStringAndSize(NULL, 40)
291+ _hexlify_sha1(PyString_AS_STRING(as_bin), PyString_AS_STRING(as_hex))
292+ return as_hex
293+
294+
295+cdef int _key_to_sha1(key, char *sha1): # cannot_raise
296+ """Map a key into its sha1 content.
297+
298+ :param key: A tuple of style ('sha1:abcd...',)
299+ :param sha1: A char buffer of 20 bytes
300+ :return: 1 if this could be converted, 0 otherwise
301+ """
302+ cdef char *c_val
303+ cdef PyObject *p_val
304+
305+ if StaticTuple_CheckExact(key) and StaticTuple_GET_SIZE(key) == 1:
306+ p_val = <PyObject *>StaticTuple_GET_ITEM(key, 0)
307+ elif (PyTuple_CheckExact(key) and PyTuple_GET_SIZE(key) == 1):
308+ p_val = PyTuple_GET_ITEM_ptr_object(key, 0)
309+ else:
310+ # Not a tuple or a StaticTuple
311+ return 0
312+ if (PyString_CheckExact_ptr(p_val) and PyString_GET_SIZE_ptr(p_val) == 45):
313+ c_val = PyString_AS_STRING_ptr(p_val)
314+ else:
315+ return 0
316+ if strncmp(c_val, 'sha1:', 5) != 0:
317+ return 0
318+ if not _unhexlify_sha1(c_val + 5, sha1):
319+ return 0
320+ return 1
321+
322+
323+def _py_key_to_sha1(key):
324+ """Map a key to a simple sha1 string.
325+
326+ This is a testing thunk to the C function.
327+ """
328+ as_bin_sha = PyString_FromStringAndSize(NULL, 20)
329+ if _key_to_sha1(key, PyString_AS_STRING(as_bin_sha)):
330+ return as_bin_sha
331+ return None
332+
333+
334+cdef StaticTuple _sha1_to_key(char *sha1):
335+ """Compute a ('sha1:abcd',) key for a given sha1."""
336+ cdef StaticTuple key
337+ cdef object hexxed
338+ cdef char *c_buf
339+ hexxed = PyString_FromStringAndSize(NULL, 45)
340+ c_buf = PyString_AS_STRING(hexxed)
341+ memcpy(c_buf, 'sha1:', 5)
342+ _hexlify_sha1(sha1, c_buf+5)
343+ key = StaticTuple_New(1)
344+ Py_INCREF(hexxed)
345+ StaticTuple_SET_ITEM(key, 0, hexxed)
346+ # This is a bit expensive. To parse 120 keys takes 48us, to return them all
347+ # can be done in 66.6us (so 18.6us to build them all).
348+ # Adding simple hash() here brings it to 76.6us (so computing the hash
349+ # value of 120keys is 10us), Intern is 86.9us (another 10us to look and add
350+ # them to the intern structure.)
351+ # However, since we only intern keys that are in active use, it is probably
352+ # a win. Since they would have been read from elsewhere anyway.
353+ # We *could* hang the PyObject form off of the gc_chk_sha1_record for ones
354+ # that we have deserialized. Something to think about, at least.
355+ key = StaticTuple_Intern(key)
356+ return key
357+
358+
359+def _py_sha1_to_key(sha1_bin):
360+ """Test thunk to check the sha1 mapping."""
361+ if not PyString_CheckExact(sha1_bin) or PyString_GET_SIZE(sha1_bin) != 20:
362+ raise ValueError('sha1_bin must be a str of exactly 20 bytes')
363+ return _sha1_to_key(PyString_AS_STRING(sha1_bin))
364+
365+
366+cdef unsigned int _sha1_to_uint(char *sha1): # cannot_raise
367+ cdef unsigned int val
368+ # Must be in MSB, because that is how the content is sorted
369+ val = (((<unsigned int>(sha1[0]) & 0xff) << 24)
370+ | ((<unsigned int>(sha1[1]) & 0xff) << 16)
371+ | ((<unsigned int>(sha1[2]) & 0xff) << 8)
372+ | ((<unsigned int>(sha1[3]) & 0xff) << 0))
373+ return val
374+
375+
376+cdef _format_record_py24(gc_chk_sha1_record *record):
377+ """Python2.4 PyString_FromFormat doesn't have %u.
378+
379+ It only has %d and %ld. We would really like to even have %llu, which
380+ is only in python2.7. So we go back into casting to regular objects.
381+ """
382+ return "%s %s %s %s" % (record.block_offset, record.block_length,
383+ record.record_start, record.record_end)
384+
385+
386+cdef _format_record(gc_chk_sha1_record *record):
387+ # This is inefficient to go from a logical state back to a
388+ # string, but it makes things work a bit better internally for now.
389+ if record.block_offset >= 0xFFFFFFFF:
390+ # %llu is what we really want, but unfortunately it was only added
391+ # in python 2.7... :(
392+ block_offset_str = str(record.block_offset)
393+ value = PyString_FromFormat('%s %lu %lu %lu',
394+ PyString_AS_STRING(block_offset_str),
395+ record.block_length,
396+ record.record_start, record.record_end)
397+ else:
398+ value = PyString_FromFormat('%lu %lu %lu %lu',
399+ <unsigned long>record.block_offset,
400+ record.block_length,
401+ record.record_start, record.record_end)
402+ return value
403+
404+ctypedef object (*formatproc)(gc_chk_sha1_record *)
405+cdef formatproc _record_formatter
406+_record_formatter = _format_record
407+if sys.version_info[:2] == (2, 4):
408+ _record_formatter = _format_record_py24
409+
410+
411+cdef class GCCHKSHA1LeafNode:
412+ """Track all the entries for a given leaf node."""
413+
414+ cdef gc_chk_sha1_record *records
415+ cdef public object last_key
416+ cdef gc_chk_sha1_record *last_record
417+ cdef public int num_records
418+ # This is the number of bits to shift to get to the interesting byte. A
419+ # value of 24 means that the very first byte changes across all keys.
420+ # Anything else means that there is a common prefix of bits that we can
421+ # ignore. 0 means that at least the first 3 bytes are identical, though
422+ # that is going to be very rare
423+ cdef public unsigned char common_shift
424+ # This maps an interesting byte to the first record that matches.
425+ # Equivalent to bisect.bisect_left(self.records, sha1), though only taking
426+ # into account that one byte.
427+ cdef unsigned char offsets[257]
428+
429+ def __sizeof__(self):
430+ # :( Why doesn't Pyrex let me do a simple sizeof(GCCHKSHA1LeafNode)
431+ # like Cython? Explicitly enumerating everything here seems to leave my
432+ # size off by 2 (286 bytes vs 288 bytes actual). I'm guessing it is an
433+ # alignment/padding issue. Oh well- at least we scale properly with
434+ # num_records and are very close to correct, which is what I care
435+ # about.
436+ # If we ever decide to require cython:
437+ # return (sizeof(GCCHKSHA1LeafNode)
438+ # + sizeof(gc_chk_sha1_record)*self.num_records)
439+ return (sizeof(PyObject) + sizeof(void*) + sizeof(int)
440+ + sizeof(gc_chk_sha1_record*) + sizeof(PyObject *)
441+ + sizeof(gc_chk_sha1_record*) + sizeof(char)
442+ + sizeof(unsigned char)*257
443+ + sizeof(gc_chk_sha1_record)*self.num_records)
444+
445+ def __dealloc__(self):
446+ if self.records != NULL:
447+ PyMem_Free(self.records)
448+ self.records = NULL
449+
450+ def __init__(self, bytes):
451+ self._parse_bytes(bytes)
452+ self.last_key = None
453+ self.last_record = NULL
454+
455+ property min_key:
456+ def __get__(self):
457+ if self.num_records > 0:
458+ return _sha1_to_key(self.records[0].sha1)
459+ return None
460+
461+ property max_key:
462+ def __get__(self):
463+ if self.num_records > 0:
464+ return _sha1_to_key(self.records[self.num_records-1].sha1)
465+ return None
466+
467+ cdef StaticTuple _record_to_value_and_refs(self,
468+ gc_chk_sha1_record *record):
469+ """Extract the refs and value part of this record."""
470+ cdef StaticTuple value_and_refs
471+ cdef StaticTuple empty
472+ value_and_refs = StaticTuple_New(2)
473+ value = _record_formatter(record)
474+ Py_INCREF(value)
475+ StaticTuple_SET_ITEM(value_and_refs, 0, value)
476+ # Always empty refs
477+ empty = StaticTuple_New(0)
478+ Py_INCREF(empty)
479+ StaticTuple_SET_ITEM(value_and_refs, 1, empty)
480+ return value_and_refs
481+
482+ cdef StaticTuple _record_to_item(self, gc_chk_sha1_record *record):
483+ """Turn a given record back into a fully fledged item.
484+ """
485+ cdef StaticTuple item
486+ cdef StaticTuple key
487+ cdef StaticTuple value_and_refs
488+ cdef object value
489+ key = _sha1_to_key(record.sha1)
490+ item = StaticTuple_New(2)
491+ Py_INCREF(key)
492+ StaticTuple_SET_ITEM(item, 0, key)
493+ value_and_refs = self._record_to_value_and_refs(record)
494+ Py_INCREF(value_and_refs)
495+ StaticTuple_SET_ITEM(item, 1, value_and_refs)
496+ return item
497+
498+ cdef gc_chk_sha1_record* _lookup_record(self, char *sha1) except? NULL:
499+ """Find a gc_chk_sha1_record that matches the sha1 supplied."""
500+ cdef int lo, hi, mid, the_cmp
501+ cdef int offset
502+
503+ # TODO: We can speed up misses by comparing this sha1 to the common
504+ # bits, and seeing if the common prefix matches, if not, we don't
505+ # need to search for anything because it cannot match
506+ # Use the offset array to find the closest fit for this entry
507+ # follow that up with bisecting, since multiple keys can be in one
508+ # spot
509+ # Bisecting dropped us from 7000 comparisons to 582 (4.8/key), using
510+ # the offset array dropped us from 23us to 20us and 156 comparisions
511+ # (1.3/key)
512+ offset = self._offset_for_sha1(sha1)
513+ lo = self.offsets[offset]
514+ hi = self.offsets[offset+1]
515+ if hi == 255:
516+ # if hi == 255 that means we potentially ran off the end of the
517+ # list, so push it up to num_records
518+ # note that if 'lo' == 255, that is ok, because we can start
519+ # searching from that part of the list.
520+ hi = self.num_records
521+ local_n_cmp = 0
522+ while lo < hi:
523+ mid = (lo + hi) / 2
524+ the_cmp = memcmp(self.records[mid].sha1, sha1, 20)
525+ if the_cmp == 0:
526+ return &self.records[mid]
527+ elif the_cmp < 0:
528+ lo = mid + 1
529+ else:
530+ hi = mid
531+ return NULL
532+
533+ def __contains__(self, key):
534+ cdef char sha1[20]
535+ cdef gc_chk_sha1_record *record
536+ if _key_to_sha1(key, sha1):
537+ # If it isn't a sha1 key, then it won't be in this leaf node
538+ record = self._lookup_record(sha1)
539+ if record != NULL:
540+ self.last_key = key
541+ self.last_record = record
542+ return True
543+ return False
544+
545+ def __getitem__(self, key):
546+ cdef char sha1[20]
547+ cdef gc_chk_sha1_record *record
548+ record = NULL
549+ if self.last_record != NULL and key is self.last_key:
550+ record = self.last_record
551+ elif _key_to_sha1(key, sha1):
552+ record = self._lookup_record(sha1)
553+ if record == NULL:
554+ raise KeyError('key %r is not present' % (key,))
555+ return self._record_to_value_and_refs(record)
556+
557+ def __len__(self):
558+ return self.num_records
559+
560+ def all_keys(self):
561+ cdef int i
562+ result = []
563+ for i from 0 <= i < self.num_records:
564+ PyList_Append(result, _sha1_to_key(self.records[i].sha1))
565+ return result
566+
567+ def all_items(self):
568+ cdef int i
569+ result = []
570+ for i from 0 <= i < self.num_records:
571+ item = self._record_to_item(&self.records[i])
572+ PyList_Append(result, item)
573+ return result
574+
575+ cdef int _count_records(self, char *c_content, char *c_end): # cannot_raise
576+ """Count how many records are in this section."""
577+ cdef char *c_cur
578+ cdef int num_records
579+
580+ c_cur = c_content
581+ num_records = 0
582+ while c_cur != NULL and c_cur < c_end:
583+ c_cur = <char *>memchr(c_cur, c'\n', c_end - c_cur);
584+ if c_cur == NULL:
585+ break
586+ c_cur = c_cur + 1
587+ num_records = num_records + 1
588+ return num_records
589+
590+ cdef _parse_bytes(self, bytes):
591+ """Parse the string 'bytes' into content."""
592+ cdef char *c_bytes
593+ cdef char *c_cur
594+ cdef char *c_end
595+ cdef Py_ssize_t n_bytes
596+ cdef int num_records
597+ cdef int entry
598+ cdef gc_chk_sha1_record *cur_record
599+
600+ if not PyString_CheckExact(bytes):
601+ raise TypeError('We only support parsing plain 8-bit strings.')
602+ # Pass 1, count how many records there will be
603+ n_bytes = PyString_GET_SIZE(bytes)
604+ c_bytes = PyString_AS_STRING(bytes)
605+ c_end = c_bytes + n_bytes
606+ if strncmp(c_bytes, 'type=leaf\n', 10):
607+ raise ValueError("bytes did not start with 'type=leaf\\n': %r"
608+ % (bytes[:10],))
609+ c_cur = c_bytes + 10
610+ num_records = self._count_records(c_cur, c_end)
611+ # Now allocate the memory for these items, and go to town
612+ self.records = <gc_chk_sha1_record*>PyMem_Malloc(num_records *
613+ (sizeof(unsigned short) + sizeof(gc_chk_sha1_record)))
614+ self.num_records = num_records
615+ cur_record = self.records
616+ entry = 0
617+ while c_cur != NULL and c_cur < c_end and entry < num_records:
618+ c_cur = self._parse_one_entry(c_cur, c_end, cur_record)
619+ cur_record = cur_record + 1
620+ entry = entry + 1
621+ if (entry != self.num_records
622+ or c_cur != c_end
623+ or cur_record != self.records + self.num_records):
624+ raise ValueError('Something went wrong while parsing.')
625+ # Pass 3: build the offset map
626+ self._compute_common()
627+
628+ cdef char *_parse_one_entry(self, char *c_cur, char *c_end,
629+ gc_chk_sha1_record *cur_record) except NULL:
630+ """Read a single sha record from the bytes.
631+ :param c_cur: The pointer to the start of bytes
632+ :param cur_record:
633+ """
634+ cdef char *c_next
635+ if strncmp(c_cur, 'sha1:', 5):
636+ raise ValueError('line did not start with sha1: %r'
637+ % (safe_string_from_size(c_cur, 10),))
638+ c_cur = c_cur + 5
639+ c_next = <char *>memchr(c_cur, c'\0', c_end - c_cur)
640+ if c_next == NULL or (c_next - c_cur != 40):
641+ raise ValueError('Line did not contain 40 hex bytes')
642+ if not _unhexlify_sha1(c_cur, cur_record.sha1):
643+ raise ValueError('We failed to unhexlify')
644+ c_cur = c_next + 1
645+ if c_cur[0] != c'\0':
646+ raise ValueError('only 1 null, not 2 as expected')
647+ c_cur = c_cur + 1
648+ cur_record.block_offset = strtoll(c_cur, &c_next, 10)
649+ if c_cur == c_next or c_next[0] != c' ':
650+ raise ValueError('Failed to parse block offset')
651+ c_cur = c_next + 1
652+ cur_record.block_length = strtoul(c_cur, &c_next, 10)
653+ if c_cur == c_next or c_next[0] != c' ':
654+ raise ValueError('Failed to parse block length')
655+ c_cur = c_next + 1
656+ cur_record.record_start = strtoul(c_cur, &c_next, 10)
657+ if c_cur == c_next or c_next[0] != c' ':
658+ raise ValueError('Failed to parse block length')
659+ c_cur = c_next + 1
660+ cur_record.record_end = strtoul(c_cur, &c_next, 10)
661+ if c_cur == c_next or c_next[0] != c'\n':
662+ raise ValueError('Failed to parse record end')
663+ c_cur = c_next + 1
664+ return c_cur
665+
666+ cdef int _offset_for_sha1(self, char *sha1) except -1:
667+ """Find the first interesting 8-bits of this sha1."""
668+ cdef int this_offset
669+ cdef unsigned int as_uint
670+ as_uint = _sha1_to_uint(sha1)
671+ this_offset = (as_uint >> self.common_shift) & 0xFF
672+ return this_offset
673+
674+ def _get_offset_for_sha1(self, sha1):
675+ return self._offset_for_sha1(PyString_AS_STRING(sha1))
676+
677+ cdef _compute_common(self):
678+ cdef unsigned int first
679+ cdef unsigned int this
680+ cdef unsigned int common_mask
681+ cdef unsigned char common_shift
682+ cdef int i
683+ cdef int offset, this_offset
684+ cdef int max_offset
685+ # The idea with the offset map is that we should be able to quickly
686+ # jump to the key that matches a gives sha1. We know that the keys are
687+ # in sorted order, and we know that a lot of the prefix is going to be
688+ # the same across them.
689+ # By XORing the records together, we can determine what bits are set in
690+ # all of them
691+ if self.num_records < 2:
692+ # Everything is in common if you have 0 or 1 leaves
693+ # So we'll always just shift to the first byte
694+ self.common_shift = 24
695+ else:
696+ common_mask = 0xFFFFFFFF
697+ first = _sha1_to_uint(self.records[0].sha1)
698+ for i from 0 < i < self.num_records:
699+ this = _sha1_to_uint(self.records[i].sha1)
700+ common_mask = (~(first ^ this)) & common_mask
701+ common_shift = 24
702+ while common_mask & 0x80000000 and common_shift > 0:
703+ common_mask = common_mask << 1
704+ common_shift = common_shift - 1
705+ self.common_shift = common_shift
706+ offset = 0
707+ max_offset = self.num_records
708+ # We cap this loop at 254 records. All the other offsets just get
709+ # filled with 0xff as the singleton saying 'too many'.
710+ # It means that if we have >255 records we have to bisect the second
711+ # half of the list, but this is going to be very rare in practice.
712+ if max_offset > 255:
713+ max_offset = 255
714+ for i from 0 <= i < max_offset:
715+ this_offset = self._offset_for_sha1(self.records[i].sha1)
716+ while offset <= this_offset:
717+ self.offsets[offset] = i
718+ offset = offset + 1
719+ while offset < 257:
720+ self.offsets[offset] = max_offset
721+ offset = offset + 1
722+
723+ def _get_offsets(self):
724+ cdef int i
725+ result = []
726+ for i from 0 <= i < 257:
727+ PyList_Append(result, self.offsets[i])
728+ return result
729+
730+
731+def _parse_into_chk(bytes, key_length, ref_list_length):
732+ """Parse into a format optimized for chk records."""
733+ assert key_length == 1
734+ assert ref_list_length == 0
735+ return GCCHKSHA1LeafNode(bytes)
736+
737+
738 def _flatten_node(node, reference_lists):
739 """Convert a node into the serialized form.
740
741
742=== modified file 'bzrlib/_chk_map_pyx.pyx'
743--- bzrlib/_chk_map_pyx.pyx 2010-05-16 15:18:43 +0000
744+++ bzrlib/_chk_map_pyx.pyx 2011-02-09 08:08:20 +0000
745@@ -413,7 +413,7 @@
746 cdef Py_ssize_t byte_size, pos, file_id_len
747
748 if not PyString_CheckExact(bytes):
749- raise TypeError('bytes must be a string')
750+ raise TypeError('bytes must be a string, got %r' % (type(bytes),))
751 byte_str = PyString_AS_STRING(bytes)
752 byte_size = PyString_GET_SIZE(bytes)
753 byte_end = byte_str + byte_size
754@@ -421,7 +421,8 @@
755 if cur_end == NULL:
756 raise ValueError('No kind section found.')
757 if cur_end[1] != c' ':
758- raise ValueError('Kind section should end with ": "')
759+ raise ValueError(
760+ 'Kind section should end with ": ", got %r' % str(cur_end[:2],))
761 file_id_str = cur_end + 2
762 # file_id is now the data up until the next newline
763 cur_end = <char*>memchr(file_id_str, c'\n', byte_end - file_id_str)
764
765=== modified file 'bzrlib/_dirstate_helpers_pyx.pyx'
766--- bzrlib/_dirstate_helpers_pyx.pyx 2010-05-20 02:57:52 +0000
767+++ bzrlib/_dirstate_helpers_pyx.pyx 2011-02-09 08:08:20 +0000
768@@ -1,4 +1,4 @@
769-# Copyright (C) 2007, 2008, 2010 Canonical Ltd
770+# Copyright (C) 2007-2010 Canonical Ltd
771 #
772 # This program is free software; you can redistribute it and/or modify
773 # it under the terms of the GNU General Public License as published by
774@@ -118,6 +118,11 @@
775 # ??? memrchr is a GNU extension :(
776 # void *memrchr(void *s, int c, size_t len)
777
778+# cimport all of the definitions we will need to access
779+from _static_tuple_c cimport import_static_tuple_c, StaticTuple, \
780+ StaticTuple_New, StaticTuple_SET_ITEM
781+
782+import_static_tuple_c()
783
784 cdef void* _my_memrchr(void *s, int c, size_t n): # cannot_raise
785 # memrchr seems to be a GNU extension, so we have to implement it ourselves
786@@ -610,7 +615,8 @@
787 :param new_block: This is to let the caller know that it needs to
788 create a new directory block to store the next entry.
789 """
790- cdef object path_name_file_id_key
791+ cdef StaticTuple path_name_file_id_key
792+ cdef StaticTuple tmp
793 cdef char *entry_size_cstr
794 cdef unsigned long int entry_size
795 cdef char* executable_cstr
796@@ -650,10 +656,20 @@
797 # Build up the key that will be used.
798 # By using <object>(void *) Pyrex will automatically handle the
799 # Py_INCREF that we need.
800- path_name_file_id_key = (<object>p_current_dirname[0],
801- self.get_next_str(),
802- self.get_next_str(),
803- )
804+ cur_dirname = <object>p_current_dirname[0]
805+ # Use StaticTuple_New to pre-allocate, rather than creating a regular
806+ # tuple and passing it to the StaticTuple constructor.
807+ # path_name_file_id_key = StaticTuple(<object>p_current_dirname[0],
808+ # self.get_next_str(),
809+ # self.get_next_str(),
810+ # )
811+ tmp = StaticTuple_New(3)
812+ Py_INCREF(cur_dirname); StaticTuple_SET_ITEM(tmp, 0, cur_dirname)
813+ cur_basename = self.get_next_str()
814+ cur_file_id = self.get_next_str()
815+ Py_INCREF(cur_basename); StaticTuple_SET_ITEM(tmp, 1, cur_basename)
816+ Py_INCREF(cur_file_id); StaticTuple_SET_ITEM(tmp, 2, cur_file_id)
817+ path_name_file_id_key = tmp
818
819 # Parse all of the per-tree information. current has the information in
820 # the same location as parent trees. The only difference is that 'info'
821@@ -677,7 +693,20 @@
822 executable_cstr = self.get_next(&cur_size)
823 is_executable = (executable_cstr[0] == c'y')
824 info = self.get_next_str()
825- PyList_Append(trees, (
826+ # TODO: If we want to use StaticTuple_New here we need to be pretty
827+ # careful. We are relying on a bit of Pyrex
828+ # automatic-conversion from 'int' to PyInt, and that doesn't
829+ # play well with the StaticTuple_SET_ITEM macro.
830+ # Timing doesn't (yet) show a worthwile improvement in speed
831+ # versus complexity and maintainability.
832+ # tmp = StaticTuple_New(5)
833+ # Py_INCREF(minikind); StaticTuple_SET_ITEM(tmp, 0, minikind)
834+ # Py_INCREF(fingerprint); StaticTuple_SET_ITEM(tmp, 1, fingerprint)
835+ # Py_INCREF(entry_size); StaticTuple_SET_ITEM(tmp, 2, entry_size)
836+ # Py_INCREF(is_executable); StaticTuple_SET_ITEM(tmp, 3, is_executable)
837+ # Py_INCREF(info); StaticTuple_SET_ITEM(tmp, 4, info)
838+ # PyList_Append(trees, tmp)
839+ PyList_Append(trees, StaticTuple(
840 minikind, # minikind
841 fingerprint, # fingerprint
842 entry_size, # size
843
844=== modified file 'bzrlib/_groupcompress_pyx.pyx'
845--- bzrlib/_groupcompress_pyx.pyx 2010-02-17 17:11:16 +0000
846+++ bzrlib/_groupcompress_pyx.pyx 2011-02-09 08:08:20 +0000
847@@ -22,6 +22,8 @@
848
849
850 cdef extern from "Python.h":
851+ ctypedef struct PyObject:
852+ pass
853 ctypedef int Py_ssize_t # Required for older pyrex versions
854 int PyString_CheckExact(object)
855 char * PyString_AS_STRING(object)
856@@ -53,6 +55,7 @@
857 unsigned long *delta_size, unsigned long max_delta_size) nogil
858 unsigned long get_delta_hdr_size(unsigned char **datap,
859 unsigned char *top) nogil
860+ unsigned long sizeof_delta_index(delta_index *index)
861 Py_ssize_t DELTA_SIZE_MIN
862
863
864@@ -91,8 +94,8 @@
865 cdef readonly object _sources
866 cdef source_info *_source_infos
867 cdef delta_index *_index
868+ cdef public unsigned long _source_offset
869 cdef readonly unsigned int _max_num_sources
870- cdef public unsigned long _source_offset
871
872 def __init__(self, source=None):
873 self._sources = []
874@@ -105,6 +108,22 @@
875 if source is not None:
876 self.add_source(source, 0)
877
878+ def __sizeof__(self):
879+ # We want to track the _source_infos allocations, but the referenced
880+ # void* are actually tracked in _sources itself.
881+ # XXX: Cython is capable of doing sizeof(class) and returning the size
882+ # of the underlying struct. Pyrex (<= 0.9.9) refuses, so we need
883+ # to do it manually. *sigh* Note that we might get it wrong
884+ # because of alignment issues.
885+ cdef Py_ssize_t size
886+ # PyObject start, vtable *, 3 object pointers, 2 C ints
887+ size = ((sizeof(PyObject) + sizeof(void*) + 3*sizeof(PyObject*)
888+ + sizeof(unsigned long)
889+ + sizeof(unsigned int))
890+ + (sizeof(source_info) * self._max_num_sources)
891+ + sizeof_delta_index(self._index))
892+ return size
893+
894 def __repr__(self):
895 return '%s(%d, %d)' % (self.__class__.__name__,
896 len(self._sources), self._source_offset)
897
898=== modified file 'bzrlib/_simple_set_pyx.pyx'
899--- bzrlib/_simple_set_pyx.pyx 2010-02-17 17:11:16 +0000
900+++ bzrlib/_simple_set_pyx.pyx 2011-02-09 08:08:20 +0000
901@@ -115,6 +115,20 @@
902 raise MemoryError()
903 memset(self._table, 0, n_bytes)
904
905+ def __sizeof__(self):
906+ # Note: Pyrex doesn't allow sizeof(class) so we re-implement it here.
907+ # Bits are:
908+ # 1: PyObject
909+ # 2: vtable *
910+ # 3: 3 Py_ssize_t
911+ # 4: PyObject**
912+ # Note that we might get alignment, etc, wrong, but at least this is
913+ # better than no estimate at all
914+ # return sizeof(SimpleSet) + (self._mask + 1) * (sizeof(PyObject*))
915+ return (sizeof(PyObject) + sizeof(void*)
916+ + 3*sizeof(Py_ssize_t) + sizeof(PyObject**)
917+ + (self._mask + 1) * sizeof(PyObject*))
918+
919 def __dealloc__(self):
920 if self._table != NULL:
921 PyMem_Free(self._table)
922
923=== modified file 'bzrlib/_static_tuple_c.pxd'
924--- bzrlib/_static_tuple_c.pxd 2010-05-11 14:13:31 +0000
925+++ bzrlib/_static_tuple_c.pxd 2011-02-09 08:08:20 +0000
926@@ -33,6 +33,7 @@
927 int import_static_tuple_c() except -1
928 StaticTuple StaticTuple_New(Py_ssize_t)
929 StaticTuple StaticTuple_Intern(StaticTuple)
930+ StaticTuple StaticTuple_FromSequence(object)
931
932 # Steals a reference and val must be a valid type, no checking is done
933 void StaticTuple_SET_ITEM(StaticTuple key, Py_ssize_t offset, object val)
934
935=== modified file 'bzrlib/branch.py'
936--- bzrlib/branch.py 2010-08-13 07:32:06 +0000
937+++ bzrlib/branch.py 2011-02-09 08:08:20 +0000
938@@ -1,4 +1,4 @@
939-# Copyright (C) 2005-2010 Canonical Ltd
940+# Copyright (C) 2005-2011 Canonical Ltd
941 #
942 # This program is free software; you can redistribute it and/or modify
943 # it under the terms of the GNU General Public License as published by
944@@ -25,8 +25,11 @@
945 bzrdir,
946 cache_utf8,
947 config as _mod_config,
948+ controldir,
949 debug,
950 errors,
951+ fetch,
952+ graph as _mod_graph,
953 lockdir,
954 lockable_files,
955 remote,
956@@ -64,7 +67,7 @@
957 BZR_BRANCH_FORMAT_6 = "Bazaar Branch Format 6 (bzr 0.15)\n"
958
959
960-class Branch(bzrdir.ControlComponent):
961+class Branch(controldir.ControlComponent):
962 """Branch holding a history of revisions.
963
964 :ivar base:
965@@ -91,6 +94,7 @@
966 self._revision_id_to_revno_cache = None
967 self._partial_revision_id_to_revno_cache = {}
968 self._partial_revision_history_cache = []
969+ self._tags_bytes = None
970 self._last_revision_info_cache = None
971 self._merge_sorted_revisions_cache = None
972 self._open_hook()
973@@ -103,6 +107,13 @@
974
975 def _activate_fallback_location(self, url):
976 """Activate the branch/repository from url as a fallback repository."""
977+ for existing_fallback_repo in self.repository._fallback_repositories:
978+ if existing_fallback_repo.user_url == url:
979+ # This fallback is already configured. This probably only
980+ # happens because BzrDir.sprout is a horrible mess. To avoid
981+ # confusing _unstack we don't add this a second time.
982+ mutter('duplicate activation of fallback %r on %r', url, self)
983+ return
984 repo = self._get_fallback_repository(url)
985 if repo.has_same_location(self.repository):
986 raise errors.UnstackableLocationError(self.user_url, url)
987@@ -226,6 +237,7 @@
988 possible_transports=[self.bzrdir.root_transport])
989 return a_branch.repository
990
991+ @needs_read_lock
992 def _get_tags_bytes(self):
993 """Get the bytes of a serialised tags dict.
994
995@@ -238,7 +250,9 @@
996 :return: The bytes of the tags file.
997 :seealso: Branch._set_tags_bytes.
998 """
999- return self._transport.get_bytes('tags')
1000+ if self._tags_bytes is None:
1001+ self._tags_bytes = self._transport.get_bytes('tags')
1002+ return self._tags_bytes
1003
1004 def _get_nick(self, local=False, possible_transports=None):
1005 config = self.get_config()
1006@@ -648,15 +662,22 @@
1007 raise errors.UnsupportedOperation(self.get_reference_info, self)
1008
1009 @needs_write_lock
1010- def fetch(self, from_branch, last_revision=None, pb=None):
1011+ def fetch(self, from_branch, last_revision=None, pb=None, fetch_spec=None):
1012 """Copy revisions from from_branch into this branch.
1013
1014 :param from_branch: Where to copy from.
1015 :param last_revision: What revision to stop at (None for at the end
1016 of the branch.
1017 :param pb: An optional progress bar to use.
1018+ :param fetch_spec: If specified, a SearchResult or
1019+ PendingAncestryResult that describes which revisions to copy. This
1020+ allows copying multiple heads at once. Mutually exclusive with
1021+ last_revision.
1022 :return: None
1023 """
1024+ if fetch_spec is not None and last_revision is not None:
1025+ raise AssertionError(
1026+ "fetch_spec and last_revision are mutually exclusive.")
1027 if self.base == from_branch.base:
1028 return (0, [])
1029 if pb is not None:
1030@@ -665,12 +686,12 @@
1031 % "pb parameter to fetch()")
1032 from_branch.lock_read()
1033 try:
1034- if last_revision is None:
1035+ if last_revision is None and fetch_spec is None:
1036 last_revision = from_branch.last_revision()
1037 last_revision = _mod_revision.ensure_null(last_revision)
1038 return self.repository.fetch(from_branch.repository,
1039 revision_id=last_revision,
1040- pb=pb)
1041+ pb=pb, fetch_spec=fetch_spec)
1042 finally:
1043 from_branch.unlock()
1044
1045@@ -804,7 +825,8 @@
1046 old_repository = self.repository
1047 if len(old_repository._fallback_repositories) != 1:
1048 raise AssertionError("can't cope with fallback repositories "
1049- "of %r" % (self.repository,))
1050+ "of %r (fallbacks: %r)" % (old_repository,
1051+ old_repository._fallback_repositories))
1052 # Open the new repository object.
1053 # Repositories don't offer an interface to remove fallback
1054 # repositories today; take the conceptually simpler option and just
1055@@ -875,8 +897,12 @@
1056
1057 :seealso: Branch._get_tags_bytes.
1058 """
1059- return _run_with_write_locked_target(self, self._transport.put_bytes,
1060- 'tags', bytes)
1061+ return _run_with_write_locked_target(self, self._set_tags_bytes_locked,
1062+ bytes)
1063+
1064+ def _set_tags_bytes_locked(self, bytes):
1065+ self._tags_bytes = bytes
1066+ return self._transport.put_bytes('tags', bytes)
1067
1068 def _cache_revision_history(self, rev_history):
1069 """Set the cached revision history to rev_history.
1070@@ -912,6 +938,7 @@
1071 self._merge_sorted_revisions_cache = None
1072 self._partial_revision_history_cache = []
1073 self._partial_revision_id_to_revno_cache = {}
1074+ self._tags_bytes = None
1075
1076 def _gen_revision_history(self):
1077 """Return sequence of revision hashes on to this branch.
1078@@ -1002,7 +1029,7 @@
1079 return other_history[self_len:stop_revision]
1080
1081 def update_revisions(self, other, stop_revision=None, overwrite=False,
1082- graph=None):
1083+ graph=None, fetch_tags=True):
1084 """Pull in new perfect-fit revisions.
1085
1086 :param other: Another Branch to pull from
1087@@ -1011,17 +1038,17 @@
1088 to see if it is a proper descendant.
1089 :param graph: A Graph object that can be used to query history
1090 information. This can be None.
1091+ :param fetch_tags: Flag that specifies if tags from other should be
1092+ fetched too.
1093 :return: None
1094 """
1095 return InterBranch.get(other, self).update_revisions(stop_revision,
1096- overwrite, graph)
1097+ overwrite, graph, fetch_tags=fetch_tags)
1098
1099+ @deprecated_method(deprecated_in((2, 4, 0)))
1100 def import_last_revision_info(self, source_repo, revno, revid):
1101 """Set the last revision info, importing from another repo if necessary.
1102
1103- This is used by the bound branch code to upload a revision to
1104- the master branch first before updating the tip of the local branch.
1105-
1106 :param source_repo: Source repository to optionally fetch from
1107 :param revno: Revision number of the new tip
1108 :param revid: Revision id of the new tip
1109@@ -1030,6 +1057,28 @@
1110 self.repository.fetch(source_repo, revision_id=revid)
1111 self.set_last_revision_info(revno, revid)
1112
1113+ def import_last_revision_info_and_tags(self, source, revno, revid):
1114+ """Set the last revision info, importing from another repo if necessary.
1115+
1116+ This is used by the bound branch code to upload a revision to
1117+ the master branch first before updating the tip of the local branch.
1118+ Revisions referenced by source's tags are also transferred.
1119+
1120+ :param source: Source branch to optionally fetch from
1121+ :param revno: Revision number of the new tip
1122+ :param revid: Revision id of the new tip
1123+ """
1124+ if not self.repository.has_same_location(source.repository):
1125+ try:
1126+ tags_to_fetch = set(source.tags.get_reverse_tag_dict())
1127+ except errors.TagsNotSupported:
1128+ tags_to_fetch = set()
1129+ fetch_spec = _mod_graph.NotInOtherForRevs(self.repository,
1130+ source.repository, [revid],
1131+ if_present_ids=tags_to_fetch).execute()
1132+ self.repository.fetch(source.repository, fetch_spec=fetch_spec)
1133+ self.set_last_revision_info(revno, revid)
1134+
1135 def revision_id_to_revno(self, revision_id):
1136 """Given a revision id, return its revno"""
1137 if _mod_revision.is_null(revision_id):
1138@@ -1256,7 +1305,8 @@
1139 return result
1140
1141 @needs_read_lock
1142- def sprout(self, to_bzrdir, revision_id=None, repository_policy=None):
1143+ def sprout(self, to_bzrdir, revision_id=None, repository_policy=None,
1144+ repository=None):
1145 """Create a new line of development from the branch, into to_bzrdir.
1146
1147 to_bzrdir controls the branch format.
1148@@ -1267,7 +1317,7 @@
1149 if (repository_policy is not None and
1150 repository_policy.requires_stacking()):
1151 to_bzrdir._format.require_stacking(_skip_repo=True)
1152- result = to_bzrdir.create_branch()
1153+ result = to_bzrdir.create_branch(repository=repository)
1154 result.lock_write()
1155 try:
1156 if repository_policy is not None:
1157@@ -1361,17 +1411,13 @@
1158 """Return the most suitable metadir for a checkout of this branch.
1159 Weaves are used if this branch's repository uses weaves.
1160 """
1161- if isinstance(self.bzrdir, bzrdir.BzrDirPreSplitOut):
1162- from bzrlib.repofmt import weaverepo
1163- format = bzrdir.BzrDirMetaFormat1()
1164- format.repository_format = weaverepo.RepositoryFormat7()
1165- else:
1166- format = self.repository.bzrdir.checkout_metadir()
1167- format.set_branch_format(self._format)
1168+ format = self.repository.bzrdir.checkout_metadir()
1169+ format.set_branch_format(self._format)
1170 return format
1171
1172 def create_clone_on_transport(self, to_transport, revision_id=None,
1173- stacked_on=None, create_prefix=False, use_existing_dir=False):
1174+ stacked_on=None, create_prefix=False, use_existing_dir=False,
1175+ no_tree=None):
1176 """Create a clone of this branch and its bzrdir.
1177
1178 :param to_transport: The transport to clone onto.
1179@@ -1390,7 +1436,8 @@
1180 revision_id = self.last_revision()
1181 dir_to = self.bzrdir.clone_on_transport(to_transport,
1182 revision_id=revision_id, stacked_on=stacked_on,
1183- create_prefix=create_prefix, use_existing_dir=use_existing_dir)
1184+ create_prefix=create_prefix, use_existing_dir=use_existing_dir,
1185+ no_tree=no_tree)
1186 return dir_to.open_branch()
1187
1188 def create_checkout(self, to_location, revision_id=None,
1189@@ -1521,7 +1568,7 @@
1190 * an open routine.
1191
1192 Formats are placed in an dict by their format string for reference
1193- during branch opening. Its not required that these be instances, they
1194+ during branch opening. It's not required that these be instances, they
1195 can be classes themselves with class methods - it simply depends on
1196 whether state is needed for a given format or not.
1197
1198@@ -1536,6 +1583,9 @@
1199 _formats = {}
1200 """The known formats."""
1201
1202+ _extra_formats = []
1203+ """Extra formats that can not be part of a metadir."""
1204+
1205 can_set_append_revisions_only = True
1206
1207 def __eq__(self, other):
1208@@ -1576,7 +1626,7 @@
1209 if isinstance(fmt, MetaDirBranchFormatFactory):
1210 fmt = fmt()
1211 result.append(fmt)
1212- return result
1213+ return result + klass._extra_formats
1214
1215 def get_reference(self, a_bzrdir, name=None):
1216 """Get the target reference of the branch in a_bzrdir.
1217@@ -1622,7 +1672,8 @@
1218 hook(params)
1219
1220 def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1221- lock_type='metadir', set_format=True):
1222+ repository=None, lock_type='metadir',
1223+ set_format=True):
1224 """Initialize a branch in a bzrdir, with specified files
1225
1226 :param a_bzrdir: The bzrdir to initialize the branch in
1227@@ -1662,11 +1713,12 @@
1228 finally:
1229 if lock_taken:
1230 control_files.unlock()
1231- branch = self.open(a_bzrdir, name, _found=True)
1232+ branch = self.open(a_bzrdir, name, _found=True,
1233+ found_repository=repository)
1234 self._run_post_branch_init_hooks(a_bzrdir, name, branch)
1235 return branch
1236
1237- def initialize(self, a_bzrdir, name=None):
1238+ def initialize(self, a_bzrdir, name=None, repository=None):
1239 """Create a branch of this format in a_bzrdir.
1240
1241 :param name: Name of the colocated branch to create.
1242@@ -1706,7 +1758,8 @@
1243 """
1244 raise NotImplementedError(self.network_name)
1245
1246- def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
1247+ def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
1248+ found_repository=None):
1249 """Return the branch object for a_bzrdir
1250
1251 :param a_bzrdir: A BzrDir that contains a branch.
1252@@ -1719,6 +1772,17 @@
1253 raise NotImplementedError(self.open)
1254
1255 @classmethod
1256+ def register_extra_format(klass, format):
1257+ """Register a branch format that can not be part of a metadir.
1258+
1259+ This is mainly useful to allow custom branch formats, such as
1260+ older Bazaar formats and foreign formats, to be tested
1261+ """
1262+ klass._extra_formats.append(format)
1263+ network_format_registry.register(
1264+ format.network_name(), format.__class__)
1265+
1266+ @classmethod
1267 def register_format(klass, format):
1268 """Register a metadir format.
1269
1270@@ -1750,6 +1814,10 @@
1271 def unregister_format(klass, format):
1272 del klass._formats[format.get_format_string()]
1273
1274+ @classmethod
1275+ def unregister_extra_format(klass, format):
1276+ klass._extra_formats.remove(format)
1277+
1278 def __str__(self):
1279 return self.get_format_description().rstrip()
1280
1281@@ -1818,7 +1886,7 @@
1282 "with a bzrlib.branch.PullResult object and only runs in the "
1283 "bzr client.", (0, 15), None))
1284 self.create_hook(HookPoint('pre_commit',
1285- "Called after a commit is calculated but before it is is "
1286+ "Called after a commit is calculated but before it is "
1287 "completed. pre_commit is called with (local, master, old_revno, "
1288 "old_revid, future_revno, future_revid, tree_delta, future_tree"
1289 "). old_revid is NULL_REVISION for the first commit to a branch, "
1290@@ -2006,8 +2074,11 @@
1291 """See BranchFormat.get_format_description()."""
1292 return "Branch format 4"
1293
1294- def initialize(self, a_bzrdir, name=None):
1295+ def initialize(self, a_bzrdir, name=None, repository=None):
1296 """Create a branch of this format in a_bzrdir."""
1297+ if repository is not None:
1298+ raise NotImplementedError(
1299+ "initialize(repository=<not None>) on %r" % (self,))
1300 utf8_files = [('revision-history', ''),
1301 ('branch-name', ''),
1302 ]
1303@@ -2022,16 +2093,19 @@
1304 """The network name for this format is the control dirs disk label."""
1305 return self._matchingbzrdir.get_format_string()
1306
1307- def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
1308+ def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
1309+ found_repository=None):
1310 """See BranchFormat.open()."""
1311 if not _found:
1312 # we are being called directly and must probe.
1313 raise NotImplementedError
1314- return BzrBranch(_format=self,
1315+ if found_repository is None:
1316+ found_repository = a_bzrdir.open_repository()
1317+ return BzrBranchPreSplitOut(_format=self,
1318 _control_files=a_bzrdir._control_files,
1319 a_bzrdir=a_bzrdir,
1320 name=name,
1321- _repository=a_bzrdir.open_repository())
1322+ _repository=found_repository)
1323
1324 def __str__(self):
1325 return "Bazaar-NG branch format 4"
1326@@ -2051,7 +2125,8 @@
1327 """
1328 return self.get_format_string()
1329
1330- def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):
1331+ def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
1332+ found_repository=None):
1333 """See BranchFormat.open()."""
1334 if not _found:
1335 format = BranchFormat.find_format(a_bzrdir, name=name)
1336@@ -2062,11 +2137,13 @@
1337 try:
1338 control_files = lockable_files.LockableFiles(transport, 'lock',
1339 lockdir.LockDir)
1340+ if found_repository is None:
1341+ found_repository = a_bzrdir.find_repository()
1342 return self._branch_class()(_format=self,
1343 _control_files=control_files,
1344 name=name,
1345 a_bzrdir=a_bzrdir,
1346- _repository=a_bzrdir.find_repository(),
1347+ _repository=found_repository,
1348 ignore_fallbacks=ignore_fallbacks)
1349 except errors.NoSuchFile:
1350 raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
1351@@ -2104,12 +2181,12 @@
1352 """See BranchFormat.get_format_description()."""
1353 return "Branch format 5"
1354
1355- def initialize(self, a_bzrdir, name=None):
1356+ def initialize(self, a_bzrdir, name=None, repository=None):
1357 """Create a branch of this format in a_bzrdir."""
1358 utf8_files = [('revision-history', ''),
1359 ('branch-name', ''),
1360 ]
1361- return self._initialize_helper(a_bzrdir, utf8_files, name)
1362+ return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
1363
1364 def supports_tags(self):
1365 return False
1366@@ -2137,13 +2214,13 @@
1367 """See BranchFormat.get_format_description()."""
1368 return "Branch format 6"
1369
1370- def initialize(self, a_bzrdir, name=None):
1371+ def initialize(self, a_bzrdir, name=None, repository=None):
1372 """Create a branch of this format in a_bzrdir."""
1373 utf8_files = [('last-revision', '0 null:\n'),
1374 ('branch.conf', ''),
1375 ('tags', ''),
1376 ]
1377- return self._initialize_helper(a_bzrdir, utf8_files, name)
1378+ return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
1379
1380 def make_tags(self, branch):
1381 """See bzrlib.branch.BranchFormat.make_tags()."""
1382@@ -2167,14 +2244,14 @@
1383 """See BranchFormat.get_format_description()."""
1384 return "Branch format 8"
1385
1386- def initialize(self, a_bzrdir, name=None):
1387+ def initialize(self, a_bzrdir, name=None, repository=None):
1388 """Create a branch of this format in a_bzrdir."""
1389 utf8_files = [('last-revision', '0 null:\n'),
1390 ('branch.conf', ''),
1391 ('tags', ''),
1392 ('references', '')
1393 ]
1394- return self._initialize_helper(a_bzrdir, utf8_files, name)
1395+ return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
1396
1397 def __init__(self):
1398 super(BzrBranchFormat8, self).__init__()
1399@@ -2203,13 +2280,13 @@
1400 This format was introduced in bzr 1.6.
1401 """
1402
1403- def initialize(self, a_bzrdir, name=None):
1404+ def initialize(self, a_bzrdir, name=None, repository=None):
1405 """Create a branch of this format in a_bzrdir."""
1406 utf8_files = [('last-revision', '0 null:\n'),
1407 ('branch.conf', ''),
1408 ('tags', ''),
1409 ]
1410- return self._initialize_helper(a_bzrdir, utf8_files, name)
1411+ return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
1412
1413 def _branch_class(self):
1414 return BzrBranch7
1415@@ -2257,7 +2334,8 @@
1416 transport = a_bzrdir.get_branch_transport(None, name=name)
1417 location = transport.put_bytes('location', to_branch.base)
1418
1419- def initialize(self, a_bzrdir, name=None, target_branch=None):
1420+ def initialize(self, a_bzrdir, name=None, target_branch=None,
1421+ repository=None):
1422 """Create a branch of this format in a_bzrdir."""
1423 if target_branch is None:
1424 # this format does not implement branch itself, thus the implicit
1425@@ -2291,7 +2369,8 @@
1426 return clone
1427
1428 def open(self, a_bzrdir, name=None, _found=False, location=None,
1429- possible_transports=None, ignore_fallbacks=False):
1430+ possible_transports=None, ignore_fallbacks=False,
1431+ found_repository=None):
1432 """Return the branch that the branch reference in a_bzrdir points at.
1433
1434 :param a_bzrdir: A BzrDir that contains a branch.
1435@@ -2349,10 +2428,7 @@
1436 BranchFormat.register_format(__format7)
1437 BranchFormat.register_format(__format8)
1438 BranchFormat.set_default_format(__format7)
1439-_legacy_formats = [BzrBranchFormat4(),
1440- ]
1441-network_format_registry.register(
1442- _legacy_formats[0].network_name(), _legacy_formats[0].__class__)
1443+BranchFormat.register_extra_format(BzrBranchFormat4())
1444
1445
1446 class BranchWriteLockResult(LogicalLockResult):
1447@@ -2634,7 +2710,7 @@
1448 result.target_branch = target
1449 result.old_revno, result.old_revid = target.last_revision_info()
1450 self.update_references(target)
1451- if result.old_revid != self.last_revision():
1452+ if result.old_revid != stop_revision:
1453 # We assume that during 'push' this repository is closer than
1454 # the target.
1455 graph = self.repository.get_graph(target.repository)
1456@@ -2663,6 +2739,19 @@
1457 mode=self.bzrdir._get_file_mode())
1458
1459
1460+class BzrBranchPreSplitOut(BzrBranch):
1461+
1462+ def _get_checkout_format(self):
1463+ """Return the most suitable metadir for a checkout of this branch.
1464+ Weaves are used if this branch's repository uses weaves.
1465+ """
1466+ from bzrlib.repofmt.weaverepo import RepositoryFormat7
1467+ from bzrlib.bzrdir import BzrDirMetaFormat1
1468+ format = BzrDirMetaFormat1()
1469+ format.repository_format = RepositoryFormat7()
1470+ return format
1471+
1472+
1473 class BzrBranch5(BzrBranch):
1474 """A format 5 branch. This supports new features over plain branches.
1475
1476@@ -3102,8 +3191,12 @@
1477 :ivar tag_conflicts: A list of tag conflicts, see BasicTags.merge_to
1478 """
1479
1480+ @deprecated_method(deprecated_in((2, 3, 0)))
1481 def __int__(self):
1482- # DEPRECATED: pull used to return the change in revno
1483+ """Return the relative change in revno.
1484+
1485+ :deprecated: Use `new_revno` and `old_revno` instead.
1486+ """
1487 return self.new_revno - self.old_revno
1488
1489 def report(self, to_file):
1490@@ -3134,8 +3227,12 @@
1491 target, otherwise it will be None.
1492 """
1493
1494+ @deprecated_method(deprecated_in((2, 3, 0)))
1495 def __int__(self):
1496- # DEPRECATED: push used to return the change in revno
1497+ """Return the relative change in revno.
1498+
1499+ :deprecated: Use `new_revno` and `old_revno` instead.
1500+ """
1501 return self.new_revno - self.old_revno
1502
1503 def report(self, to_file):
1504@@ -3287,7 +3384,7 @@
1505
1506 @needs_write_lock
1507 def update_revisions(self, stop_revision=None, overwrite=False,
1508- graph=None):
1509+ graph=None, fetch_tags=True):
1510 """Pull in new perfect-fit revisions.
1511
1512 :param stop_revision: Updated until the given revision
1513@@ -3295,6 +3392,8 @@
1514 to see if it is a proper descendant.
1515 :param graph: A Graph object that can be used to query history
1516 information. This can be None.
1517+ :param fetch_tags: Flag that specifies if tags from source should be
1518+ fetched too.
1519 :return: None
1520 """
1521 raise NotImplementedError(self.update_revisions)
1522@@ -3308,6 +3407,15 @@
1523 """
1524 raise NotImplementedError(self.push)
1525
1526+ @needs_write_lock
1527+ def copy_content_into(self, revision_id=None):
1528+ """Copy the content of source into target
1529+
1530+ revision_id: if not None, the revision history in the new branch will
1531+ be truncated to end with revision_id.
1532+ """
1533+ raise NotImplementedError(self.copy_content_into)
1534+
1535
1536 class GenericInterBranch(InterBranch):
1537 """InterBranch implementation that uses public Branch functions."""
1538@@ -3326,7 +3434,7 @@
1539 if isinstance(format, remote.RemoteBranchFormat):
1540 format._ensure_real()
1541 return format._custom_format
1542- return format
1543+ return format
1544
1545 @needs_write_lock
1546 def copy_content_into(self, revision_id=None):
1547@@ -3349,7 +3457,7 @@
1548
1549 @needs_write_lock
1550 def update_revisions(self, stop_revision=None, overwrite=False,
1551- graph=None):
1552+ graph=None, fetch_tags=True):
1553 """See InterBranch.update_revisions()."""
1554 other_revno, other_last_revision = self.source.last_revision_info()
1555 stop_revno = None # unknown
1556@@ -3367,7 +3475,18 @@
1557 # case of having something to pull, and so that the check for
1558 # already merged can operate on the just fetched graph, which will
1559 # be cached in memory.
1560- self.target.fetch(self.source, stop_revision)
1561+ if fetch_tags:
1562+ fetch_spec_factory = fetch.FetchSpecFactory()
1563+ fetch_spec_factory.source_branch = self.source
1564+ fetch_spec_factory.source_branch_stop_revision_id = stop_revision
1565+ fetch_spec_factory.source_repo = self.source.repository
1566+ fetch_spec_factory.target_repo = self.target.repository
1567+ fetch_spec_factory.target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
1568+ fetch_spec = fetch_spec_factory.make_fetch_spec()
1569+ else:
1570+ fetch_spec = _mod_graph.NotInOtherForRevs(self.target.repository,
1571+ self.source.repository, revision_ids=[stop_revision]).execute()
1572+ self.target.fetch(self.source, fetch_spec=fetch_spec)
1573 # Check to see if one is an ancestor of the other
1574 if not overwrite:
1575 if graph is None:
1576@@ -3401,7 +3520,8 @@
1577 if local and not bound_location:
1578 raise errors.LocalRequiresBoundBranch()
1579 master_branch = None
1580- if not local and bound_location and self.source.user_url != bound_location:
1581+ source_is_master = (self.source.user_url == bound_location)
1582+ if not local and bound_location and not source_is_master:
1583 # not pulling from master, so we need to update master.
1584 master_branch = self.target.get_master_branch(possible_transports)
1585 master_branch.lock_write()
1586@@ -3413,7 +3533,8 @@
1587 return self._pull(overwrite,
1588 stop_revision, _hook_master=master_branch,
1589 run_hooks=run_hooks,
1590- _override_hook_target=_override_hook_target)
1591+ _override_hook_target=_override_hook_target,
1592+ merge_tags_to_master=not source_is_master)
1593 finally:
1594 if master_branch:
1595 master_branch.unlock()
1596@@ -3462,7 +3583,7 @@
1597 # push into the master from the source branch.
1598 self.source._basic_push(master_branch, overwrite, stop_revision)
1599 # and push into the target branch from the source. Note that we
1600- # push from the source branch again, because its considered the
1601+ # push from the source branch again, because it's considered the
1602 # highest bandwidth repository.
1603 result = self.source._basic_push(self.target, overwrite,
1604 stop_revision)
1605@@ -3486,7 +3607,8 @@
1606
1607 def _pull(self, overwrite=False, stop_revision=None,
1608 possible_transports=None, _hook_master=None, run_hooks=True,
1609- _override_hook_target=None, local=False):
1610+ _override_hook_target=None, local=False,
1611+ merge_tags_to_master=True):
1612 """See Branch.pull.
1613
1614 This function is the core worker, used by GenericInterBranch.pull to
1615@@ -3527,7 +3649,7 @@
1616 # so a tags implementation that versions tags can only
1617 # pull in the most recent changes. -- JRV20090506
1618 result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
1619- overwrite)
1620+ overwrite, ignore_master=not merge_tags_to_master)
1621 result.new_revno, result.new_revid = self.target.last_revision_info()
1622 if _hook_master:
1623 result.master_branch = _hook_master
1624
1625=== modified file 'bzrlib/branchbuilder.py'
1626--- bzrlib/branchbuilder.py 2010-02-27 12:27:33 +0000
1627+++ bzrlib/branchbuilder.py 2011-02-09 08:08:20 +0000
1628@@ -21,6 +21,7 @@
1629 commit,
1630 errors,
1631 memorytree,
1632+ revision,
1633 )
1634
1635
1636@@ -186,7 +187,10 @@
1637 :return: The revision_id of the new commit
1638 """
1639 if parent_ids is not None:
1640- base_id = parent_ids[0]
1641+ if len(parent_ids) == 0:
1642+ base_id = revision.NULL_REVISION
1643+ else:
1644+ base_id = parent_ids[0]
1645 if base_id != self._branch.last_revision():
1646 self._move_branch_pointer(base_id,
1647 allow_leftmost_as_ghost=allow_leftmost_as_ghost)
1648
1649=== modified file 'bzrlib/btree_index.py'
1650--- bzrlib/btree_index.py 2010-06-20 11:18:38 +0000
1651+++ bzrlib/btree_index.py 2011-02-09 08:08:20 +0000
1652@@ -602,10 +602,10 @@
1653 """In memory index's have no known corruption at the moment."""
1654
1655
1656-class _LeafNode(object):
1657+class _LeafNode(dict):
1658 """A leaf node for a serialised B+Tree index."""
1659
1660- __slots__ = ('keys', 'min_key', 'max_key')
1661+ __slots__ = ('min_key', 'max_key', '_keys')
1662
1663 def __init__(self, bytes, key_length, ref_list_length):
1664 """Parse bytes to create a leaf node object."""
1665@@ -617,7 +617,20 @@
1666 self.max_key = key_list[-1][0]
1667 else:
1668 self.min_key = self.max_key = None
1669- self.keys = dict(key_list)
1670+ super(_LeafNode, self).__init__(key_list)
1671+ self._keys = dict(self)
1672+
1673+ def all_items(self):
1674+ """Return a sorted list of (key, (value, refs)) items"""
1675+ items = self.items()
1676+ items.sort()
1677+ return items
1678+
1679+ def all_keys(self):
1680+ """Return a sorted list of all keys."""
1681+ keys = self.keys()
1682+ keys.sort()
1683+ return keys
1684
1685
1686 class _InternalNode(object):
1687@@ -672,6 +685,7 @@
1688 self._recommended_pages = self._compute_recommended_pages()
1689 self._root_node = None
1690 self._base_offset = offset
1691+ self._leaf_factory = _LeafNode
1692 # Default max size is 100,000 leave values
1693 self._leaf_value_cache = None # lru_cache.LRUCache(100*1000)
1694 if unlimited_cache:
1695@@ -950,7 +964,7 @@
1696 """Cache directly from key => value, skipping the btree."""
1697 if self._leaf_value_cache is not None:
1698 for node in nodes.itervalues():
1699- for key, value in node.keys.iteritems():
1700+ for key, value in node.all_items():
1701 if key in self._leaf_value_cache:
1702 # Don't add the rest of the keys, we've seen this node
1703 # before.
1704@@ -980,10 +994,10 @@
1705 if self._row_offsets[-1] == 1:
1706 # There is only the root node, and we read that via key_count()
1707 if self.node_ref_lists:
1708- for key, (value, refs) in sorted(self._root_node.keys.items()):
1709+ for key, (value, refs) in self._root_node.all_items():
1710 yield (self, key, value, refs)
1711 else:
1712- for key, (value, refs) in sorted(self._root_node.keys.items()):
1713+ for key, (value, refs) in self._root_node.all_items():
1714 yield (self, key, value)
1715 return
1716 start_of_leaves = self._row_offsets[-2]
1717@@ -999,11 +1013,11 @@
1718 # for spilling index builds to disk.
1719 if self.node_ref_lists:
1720 for _, node in nodes:
1721- for key, (value, refs) in sorted(node.keys.items()):
1722+ for key, (value, refs) in node.all_items():
1723 yield (self, key, value, refs)
1724 else:
1725 for _, node in nodes:
1726- for key, (value, refs) in sorted(node.keys.items()):
1727+ for key, (value, refs) in node.all_items():
1728 yield (self, key, value)
1729
1730 @staticmethod
1731@@ -1170,8 +1184,8 @@
1732 continue
1733 node = nodes[node_index]
1734 for next_sub_key in sub_keys:
1735- if next_sub_key in node.keys:
1736- value, refs = node.keys[next_sub_key]
1737+ if next_sub_key in node:
1738+ value, refs = node[next_sub_key]
1739 if self.node_ref_lists:
1740 yield (self, next_sub_key, value, refs)
1741 else:
1742@@ -1245,14 +1259,13 @@
1743 # sub_keys is all of the keys we are looking for that should exist
1744 # on this page, if they aren't here, then they won't be found
1745 node = nodes[node_index]
1746- node_keys = node.keys
1747 parents_to_check = set()
1748 for next_sub_key in sub_keys:
1749- if next_sub_key not in node_keys:
1750+ if next_sub_key not in node:
1751 # This one is just not present in the index at all
1752 missing_keys.add(next_sub_key)
1753 else:
1754- value, refs = node_keys[next_sub_key]
1755+ value, refs = node[next_sub_key]
1756 parent_keys = refs[ref_list_num]
1757 parent_map[next_sub_key] = parent_keys
1758 parents_to_check.update(parent_keys)
1759@@ -1265,8 +1278,8 @@
1760 while parents_to_check:
1761 next_parents_to_check = set()
1762 for key in parents_to_check:
1763- if key in node_keys:
1764- value, refs = node_keys[key]
1765+ if key in node:
1766+ value, refs = node[key]
1767 parent_keys = refs[ref_list_num]
1768 parent_map[key] = parent_keys
1769 next_parents_to_check.update(parent_keys)
1770@@ -1546,7 +1559,8 @@
1771 continue
1772 bytes = zlib.decompress(data)
1773 if bytes.startswith(_LEAF_FLAG):
1774- node = _LeafNode(bytes, self._key_length, self.node_ref_lists)
1775+ node = self._leaf_factory(bytes, self._key_length,
1776+ self.node_ref_lists)
1777 elif bytes.startswith(_INTERNAL_FLAG):
1778 node = _InternalNode(bytes)
1779 else:
1780@@ -1571,8 +1585,11 @@
1781 pass
1782
1783
1784+_gcchk_factory = _LeafNode
1785+
1786 try:
1787 from bzrlib import _btree_serializer_pyx as _btree_serializer
1788+ _gcchk_factory = _btree_serializer._parse_into_chk
1789 except ImportError, e:
1790 osutils.failed_to_load_extension(e)
1791 from bzrlib import _btree_serializer_py as _btree_serializer
1792
1793=== modified file 'bzrlib/bugtracker.py'
1794--- bzrlib/bugtracker.py 2010-04-30 11:03:59 +0000
1795+++ bzrlib/bugtracker.py 2011-02-09 08:08:20 +0000
1796@@ -93,7 +93,7 @@
1797 --fixes`` to mark bugs in that tracker as being fixed by that commit. For
1798 example::
1799
1800- bugzilla_squid_url = http://www.squid-cache.org/bugs
1801+ bugzilla_squid_url = http://bugs.squid-cache.org
1802
1803 would allow ``bzr commit --fixes squid:1234`` to mark Squid's bug 1234 as
1804 fixed.
1805@@ -127,7 +127,13 @@
1806
1807 bugtracker_cpan_url = http://rt.cpan.org/Public/Bug/Display.html?id={id}
1808
1809-for CPAN's RT bug tracker.
1810+would allow ``bzr commit --fixes cpan:1234`` to mark bug 1234 in CPAN's
1811+RT bug tracker as fixed, or::
1812+
1813+ bugtracker_hudson_url = http://issues.hudson-ci.org/browse/{id}
1814+
1815+would allow ``bzr commit --fixes hudson:HUDSON-1234`` to mark bug HUDSON-1234
1816+in Hudson's JIRA bug tracker as fixed.
1817 """
1818
1819
1820@@ -228,14 +234,13 @@
1821 UniqueIntegerBugTracker('gnome', 'http://bugzilla.gnome.org/show_bug.cgi?id='))
1822
1823
1824-class URLParametrizedIntegerBugTracker(IntegerBugTracker):
1825+class URLParametrizedBugTracker(BugTracker):
1826 """A type of bug tracker that can be found on a variety of different sites,
1827 and thus needs to have the base URL configured.
1828
1829 Looks for a config setting in the form '<type_name>_<abbreviation>_url'.
1830- `type_name` is the name of the type of tracker (e.g. 'bugzilla' or 'trac')
1831- and `abbreviation` is a short name for the particular instance (e.g.
1832- 'squid' or 'apache').
1833+ `type_name` is the name of the type of tracker and `abbreviation`
1834+ is a short name for the particular instance.
1835 """
1836
1837 def get(self, abbreviation, branch):
1838@@ -256,6 +261,16 @@
1839 return urlutils.join(self._base_url, self._bug_area) + str(bug_id)
1840
1841
1842+class URLParametrizedIntegerBugTracker(IntegerBugTracker, URLParametrizedBugTracker):
1843+ """A type of bug tracker that can be found on a variety of different sites,
1844+ and thus needs to have the base URL configured, but only allows integer bug IDs.
1845+
1846+ Looks for a config setting in the form '<type_name>_<abbreviation>_url'.
1847+ `type_name` is the name of the type of tracker (e.g. 'bugzilla' or 'trac')
1848+ and `abbreviation` is a short name for the particular instance (e.g.
1849+ 'squid' or 'apache').
1850+ """
1851+
1852 tracker_registry.register(
1853 'trac', URLParametrizedIntegerBugTracker('trac', 'ticket/'))
1854
1855@@ -264,7 +279,7 @@
1856 URLParametrizedIntegerBugTracker('bugzilla', 'show_bug.cgi?id='))
1857
1858
1859-class GenericBugTracker(URLParametrizedIntegerBugTracker):
1860+class GenericBugTracker(URLParametrizedBugTracker):
1861 """Generic bug tracker specified by an URL template."""
1862
1863 def __init__(self):
1864
1865=== modified file 'bzrlib/builtins.py'
1866--- bzrlib/builtins.py 2010-07-28 07:05:19 +0000
1867+++ bzrlib/builtins.py 2011-02-09 08:08:20 +0000
1868@@ -1,4 +1,4 @@
1869-# Copyright (C) 2005-2010 Canonical Ltd
1870+# Copyright (C) 2005-2011 Canonical Ltd
1871 #
1872 # This program is free software; you can redistribute it and/or modify
1873 # it under the terms of the GNU General Public License as published by
1874@@ -20,7 +20,6 @@
1875
1876 from bzrlib.lazy_import import lazy_import
1877 lazy_import(globals(), """
1878-import codecs
1879 import cStringIO
1880 import sys
1881 import time
1882@@ -33,7 +32,7 @@
1883 bzrdir,
1884 directory_service,
1885 delta,
1886- config,
1887+ config as _mod_config,
1888 errors,
1889 globbing,
1890 hooks,
1891@@ -75,14 +74,11 @@
1892 from bzrlib.trace import mutter, note, warning, is_quiet, get_verbosity_level
1893
1894
1895+@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
1896 def tree_files(file_list, default_branch=u'.', canonicalize=True,
1897 apply_view=True):
1898- try:
1899- return internal_tree_files(file_list, default_branch, canonicalize,
1900- apply_view)
1901- except errors.FileInWrongBranch, e:
1902- raise errors.BzrCommandError("%s is not in the same branch as %s" %
1903- (e.path, file_list[0]))
1904+ return internal_tree_files(file_list, default_branch, canonicalize,
1905+ apply_view)
1906
1907
1908 def tree_files_for_add(file_list):
1909@@ -152,10 +148,13 @@
1910
1911 # XXX: Bad function name; should possibly also be a class method of
1912 # WorkingTree rather than a function.
1913+@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
1914 def internal_tree_files(file_list, default_branch=u'.', canonicalize=True,
1915 apply_view=True):
1916 """Convert command-line paths to a WorkingTree and relative paths.
1917
1918+ Deprecated: use WorkingTree.open_containing_paths instead.
1919+
1920 This is typically used for command-line processors that take one or
1921 more filenames, and infer the workingtree that contains them.
1922
1923@@ -171,53 +170,10 @@
1924
1925 :return: workingtree, [relative_paths]
1926 """
1927- if file_list is None or len(file_list) == 0:
1928- tree = WorkingTree.open_containing(default_branch)[0]
1929- if tree.supports_views() and apply_view:
1930- view_files = tree.views.lookup_view()
1931- if view_files:
1932- file_list = view_files
1933- view_str = views.view_display_str(view_files)
1934- note("Ignoring files outside view. View is %s" % view_str)
1935- return tree, file_list
1936- tree = WorkingTree.open_containing(file_list[0])[0]
1937- return tree, safe_relpath_files(tree, file_list, canonicalize,
1938- apply_view=apply_view)
1939-
1940-
1941-def safe_relpath_files(tree, file_list, canonicalize=True, apply_view=True):
1942- """Convert file_list into a list of relpaths in tree.
1943-
1944- :param tree: A tree to operate on.
1945- :param file_list: A list of user provided paths or None.
1946- :param apply_view: if True and a view is set, apply it or check that
1947- specified files are within it
1948- :return: A list of relative paths.
1949- :raises errors.PathNotChild: When a provided path is in a different tree
1950- than tree.
1951- """
1952- if file_list is None:
1953- return None
1954- if tree.supports_views() and apply_view:
1955- view_files = tree.views.lookup_view()
1956- else:
1957- view_files = []
1958- new_list = []
1959- # tree.relpath exists as a "thunk" to osutils, but canonical_relpath
1960- # doesn't - fix that up here before we enter the loop.
1961- if canonicalize:
1962- fixer = lambda p: osutils.canonical_relpath(tree.basedir, p)
1963- else:
1964- fixer = tree.relpath
1965- for filename in file_list:
1966- try:
1967- relpath = fixer(osutils.dereference_path(filename))
1968- if view_files and not osutils.is_inside_any(view_files, relpath):
1969- raise errors.FileOutsideView(filename, view_files)
1970- new_list.append(relpath)
1971- except errors.PathNotChild:
1972- raise errors.FileInWrongBranch(tree.branch, filename)
1973- return new_list
1974+ return WorkingTree.open_containing_paths(
1975+ file_list, default_directory='.',
1976+ canonicalize=True,
1977+ apply_view=True)
1978
1979
1980 def _get_view_info_for_change_reporter(tree):
1981@@ -294,8 +250,12 @@
1982 To skip the display of pending merge information altogether, use
1983 the no-pending option or specify a file/directory.
1984
1985- If a revision argument is given, the status is calculated against
1986- that revision, or between two revisions if two are provided.
1987+ To compare the working directory to a specific revision, pass a
1988+ single revision to the revision argument.
1989+
1990+ To see which files have changed in a specific revision, or between
1991+ two revisions, pass a revision range to the revision argument.
1992+ This will produce the same results as calling 'bzr diff --summarize'.
1993 """
1994
1995 # TODO: --no-recurse, --recurse options
1996@@ -323,7 +283,7 @@
1997 raise errors.BzrCommandError('bzr status --revision takes exactly'
1998 ' one or two revision specifiers')
1999
2000- tree, relfile_list = tree_files(file_list)
2001+ tree, relfile_list = WorkingTree.open_containing_paths(file_list)
2002 # Avoid asking for specific files when that is not needed.
2003 if relfile_list == ['']:
2004 relfile_list = None
2005@@ -368,7 +328,8 @@
2006 if revision_id is None and revision is None:
2007 raise errors.BzrCommandError('You must supply either'
2008 ' --revision or a revision_id')
2009- b = WorkingTree.open_containing(directory)[0].branch
2010+
2011+ b = bzrdir.BzrDir.open_containing_tree_or_branch(directory)[1]
2012
2013 revisions = b.repository.revisions
2014 if revisions is None:
2015@@ -521,6 +482,59 @@
2016 d.destroy_workingtree()
2017
2018
2019+class cmd_repair_workingtree(Command):
2020+ __doc__ = """Reset the working tree state file.
2021+
2022+ This is not meant to be used normally, but more as a way to recover from
2023+ filesystem corruption, etc. This rebuilds the working inventory back to a
2024+ 'known good' state. Any new modifications (adding a file, renaming, etc)
2025+ will be lost, though modified files will still be detected as such.
2026+
2027+ Most users will want something more like "bzr revert" or "bzr update"
2028+ unless the state file has become corrupted.
2029+
2030+ By default this attempts to recover the current state by looking at the
2031+ headers of the state file. If the state file is too corrupted to even do
2032+ that, you can supply --revision to force the state of the tree.
2033+ """
2034+
2035+ takes_options = ['revision', 'directory',
2036+ Option('force',
2037+ help='Reset the tree even if it doesn\'t appear to be'
2038+ ' corrupted.'),
2039+ ]
2040+ hidden = True
2041+
2042+ def run(self, revision=None, directory='.', force=False):
2043+ tree, _ = WorkingTree.open_containing(directory)
2044+ self.add_cleanup(tree.lock_tree_write().unlock)
2045+ if not force:
2046+ try:
2047+ tree.check_state()
2048+ except errors.BzrError:
2049+ pass # There seems to be a real error here, so we'll reset
2050+ else:
2051+ # Refuse
2052+ raise errors.BzrCommandError(
2053+ 'The tree does not appear to be corrupt. You probably'
2054+ ' want "bzr revert" instead. Use "--force" if you are'
2055+ ' sure you want to reset the working tree.')
2056+ if revision is None:
2057+ revision_ids = None
2058+ else:
2059+ revision_ids = [r.as_revision_id(tree.branch) for r in revision]
2060+ try:
2061+ tree.reset_state(revision_ids)
2062+ except errors.BzrError, e:
2063+ if revision_ids is None:
2064+ extra = (', the header appears corrupt, try passing -r -1'
2065+ ' to set the state to the last commit')
2066+ else:
2067+ extra = ''
2068+ raise errors.BzrCommandError('failed to reset the tree state'
2069+ + extra)
2070+
2071+
2072 class cmd_revno(Command):
2073 __doc__ = """Show current revision number.
2074
2075@@ -761,7 +775,7 @@
2076 raise errors.BzrCommandError('invalid kind %r specified' % (kind,))
2077
2078 revision = _get_one_revision('inventory', revision)
2079- work_tree, file_list = tree_files(file_list)
2080+ work_tree, file_list = WorkingTree.open_containing_paths(file_list)
2081 self.add_cleanup(work_tree.lock_read().unlock)
2082 if revision is not None:
2083 tree = revision.as_tree(work_tree.branch)
2084@@ -832,7 +846,7 @@
2085 names_list = []
2086 if len(names_list) < 2:
2087 raise errors.BzrCommandError("missing file argument")
2088- tree, rel_names = tree_files(names_list, canonicalize=False)
2089+ tree, rel_names = WorkingTree.open_containing_paths(names_list, canonicalize=False)
2090 self.add_cleanup(tree.lock_tree_write().unlock)
2091 self._run(tree, names_list, rel_names, after)
2092
2093@@ -843,7 +857,8 @@
2094 if after:
2095 raise errors.BzrCommandError('--after cannot be specified with'
2096 ' --auto.')
2097- work_tree, file_list = tree_files(names_list, default_branch='.')
2098+ work_tree, file_list = WorkingTree.open_containing_paths(
2099+ names_list, default_directory='.')
2100 self.add_cleanup(work_tree.lock_tree_write().unlock)
2101 rename_map.RenameMap.guess_renames(work_tree, dry_run)
2102
2103@@ -966,13 +981,16 @@
2104 "branch. Local pulls are not applied to "
2105 "the master branch."
2106 ),
2107+ Option('show-base',
2108+ help="Show base revision text in conflicts.")
2109 ]
2110 takes_args = ['location?']
2111 encoding_type = 'replace'
2112
2113 def run(self, location=None, remember=False, overwrite=False,
2114 revision=None, verbose=False,
2115- directory=None, local=False):
2116+ directory=None, local=False,
2117+ show_base=False):
2118 # FIXME: too much stuff is in the command class
2119 revision_id = None
2120 mergeable = None
2121@@ -987,6 +1005,9 @@
2122 branch_to = Branch.open_containing(directory)[0]
2123 self.add_cleanup(branch_to.lock_write().unlock)
2124
2125+ if tree_to is None and show_base:
2126+ raise errors.BzrCommandError("Need working tree for --show-base.")
2127+
2128 if local and not branch_to.get_bound_location():
2129 raise errors.LocalRequiresBoundBranch()
2130
2131@@ -1037,7 +1058,8 @@
2132 view_info=view_info)
2133 result = tree_to.pull(
2134 branch_from, overwrite, revision_id, change_reporter,
2135- possible_transports=possible_transports, local=local)
2136+ possible_transports=possible_transports, local=local,
2137+ show_base=show_base)
2138 else:
2139 result = branch_to.pull(
2140 branch_from, overwrite, revision_id, local=local)
2141@@ -1047,6 +1069,10 @@
2142 log.show_branch_change(
2143 branch_to, self.outf, result.old_revno,
2144 result.old_revid)
2145+ if getattr(result, 'tag_conflicts', None):
2146+ return 1
2147+ else:
2148+ return 0
2149
2150
2151 class cmd_push(Command):
2152@@ -1099,6 +1125,9 @@
2153 Option('strict',
2154 help='Refuse to push if there are uncommitted changes in'
2155 ' the working tree, --no-strict disables the check.'),
2156+ Option('no-tree',
2157+ help="Don't populate the working tree, even for protocols"
2158+ " that support it."),
2159 ]
2160 takes_args = ['location?']
2161 encoding_type = 'replace'
2162@@ -1106,7 +1135,7 @@
2163 def run(self, location=None, remember=False, overwrite=False,
2164 create_prefix=False, verbose=False, revision=None,
2165 use_existing_dir=False, directory=None, stacked_on=None,
2166- stacked=False, strict=None):
2167+ stacked=False, strict=None, no_tree=False):
2168 from bzrlib.push import _show_push_branch
2169
2170 if directory is None:
2171@@ -1158,7 +1187,7 @@
2172 _show_push_branch(br_from, revision_id, location, self.outf,
2173 verbose=verbose, overwrite=overwrite, remember=remember,
2174 stacked_on=stacked_on, create_prefix=create_prefix,
2175- use_existing_dir=use_existing_dir)
2176+ use_existing_dir=use_existing_dir, no_tree=no_tree)
2177
2178
2179 class cmd_branch(Command):
2180@@ -1177,8 +1206,10 @@
2181
2182 _see_also = ['checkout']
2183 takes_args = ['from_location', 'to_location?']
2184- takes_options = ['revision', Option('hardlink',
2185- help='Hard-link working tree files where possible.'),
2186+ takes_options = ['revision',
2187+ Option('hardlink', help='Hard-link working tree files where possible.'),
2188+ Option('files-from', type=str,
2189+ help="Get file contents from this tree."),
2190 Option('no-tree',
2191 help="Create a branch without a working-tree."),
2192 Option('switch',
2193@@ -1202,11 +1233,19 @@
2194
2195 def run(self, from_location, to_location=None, revision=None,
2196 hardlink=False, stacked=False, standalone=False, no_tree=False,
2197- use_existing_dir=False, switch=False, bind=False):
2198+ use_existing_dir=False, switch=False, bind=False,
2199+ files_from=None):
2200 from bzrlib import switch as _mod_switch
2201 from bzrlib.tag import _merge_tags_if_possible
2202 accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
2203 from_location)
2204+ if not (hardlink or files_from):
2205+ # accelerator_tree is usually slower because you have to read N
2206+ # files (no readahead, lots of seeks, etc), but allow the user to
2207+ # explicitly request it
2208+ accelerator_tree = None
2209+ if files_from is not None and files_from != from_location:
2210+ accelerator_tree = WorkingTree.open(files_from)
2211 revision = _get_one_revision('branch', revision)
2212 self.add_cleanup(br_from.lock_read().unlock)
2213 if revision is not None:
2214@@ -1319,8 +1358,13 @@
2215 to_location = branch_location
2216 accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(
2217 branch_location)
2218+ if not (hardlink or files_from):
2219+ # accelerator_tree is usually slower because you have to read N
2220+ # files (no readahead, lots of seeks, etc), but allow the user to
2221+ # explicitly request it
2222+ accelerator_tree = None
2223 revision = _get_one_revision('checkout', revision)
2224- if files_from is not None:
2225+ if files_from is not None and files_from != branch_location:
2226 accelerator_tree = WorkingTree.open(files_from)
2227 if revision is not None:
2228 revision_id = revision.as_revision_id(source)
2229@@ -1382,16 +1426,22 @@
2230 If you want to discard your local changes, you can just do a
2231 'bzr revert' instead of 'bzr commit' after the update.
2232
2233+ If you want to restore a file that has been removed locally, use
2234+ 'bzr revert' instead of 'bzr update'.
2235+
2236 If the tree's branch is bound to a master branch, it will also update
2237 the branch from the master.
2238 """
2239
2240 _see_also = ['pull', 'working-trees', 'status-flags']
2241 takes_args = ['dir?']
2242- takes_options = ['revision']
2243+ takes_options = ['revision',
2244+ Option('show-base',
2245+ help="Show base revision text in conflicts."),
2246+ ]
2247 aliases = ['up']
2248
2249- def run(self, dir='.', revision=None):
2250+ def run(self, dir='.', revision=None, show_base=None):
2251 if revision is not None and len(revision) != 1:
2252 raise errors.BzrCommandError(
2253 "bzr update --revision takes exactly one revision")
2254@@ -1437,7 +1487,8 @@
2255 change_reporter,
2256 possible_transports=possible_transports,
2257 revision=revision_id,
2258- old_tip=old_tip)
2259+ old_tip=old_tip,
2260+ show_base=show_base)
2261 except errors.NoSuchRevision, e:
2262 raise errors.BzrCommandError(
2263 "branch has no revision %s\n"
2264@@ -1505,10 +1556,11 @@
2265 class cmd_remove(Command):
2266 __doc__ = """Remove files or directories.
2267
2268- This makes bzr stop tracking changes to the specified files. bzr will delete
2269- them if they can easily be recovered using revert. If no options or
2270- parameters are given bzr will scan for files that are being tracked by bzr
2271- but missing in your tree and stop tracking them for you.
2272+ This makes Bazaar stop tracking changes to the specified files. Bazaar will
2273+ delete them if they can easily be recovered using revert otherwise they
2274+ will be backed up (adding an extention of the form .~#~). If no options or
2275+ parameters are given Bazaar will scan for files that are being tracked by
2276+ Bazaar but missing in your tree and stop tracking them for you.
2277 """
2278 takes_args = ['file*']
2279 takes_options = ['verbose',
2280@@ -1516,17 +1568,23 @@
2281 RegistryOption.from_kwargs('file-deletion-strategy',
2282 'The file deletion mode to be used.',
2283 title='Deletion Strategy', value_switches=True, enum_switch=False,
2284- safe='Only delete files if they can be'
2285- ' safely recovered (default).',
2286+ safe='Backup changed files (default).',
2287 keep='Delete from bzr but leave the working copy.',
2288+ no_backup='Don\'t backup changed files.',
2289 force='Delete all the specified files, even if they can not be '
2290- 'recovered and even if they are non-empty directories.')]
2291+ 'recovered and even if they are non-empty directories. '
2292+ '(deprecated, use no-backup)')]
2293 aliases = ['rm', 'del']
2294 encoding_type = 'replace'
2295
2296 def run(self, file_list, verbose=False, new=False,
2297 file_deletion_strategy='safe'):
2298- tree, file_list = tree_files(file_list)
2299+ if file_deletion_strategy == 'force':
2300+ note("(The --force option is deprecated, rather use --no-backup "
2301+ "in future.)")
2302+ file_deletion_strategy = 'no-backup'
2303+
2304+ tree, file_list = WorkingTree.open_containing_paths(file_list)
2305
2306 if file_list is not None:
2307 file_list = [f for f in file_list]
2308@@ -1552,7 +1610,7 @@
2309 file_deletion_strategy = 'keep'
2310 tree.remove(file_list, verbose=verbose, to_file=self.outf,
2311 keep_files=file_deletion_strategy=='keep',
2312- force=file_deletion_strategy=='force')
2313+ force=(file_deletion_strategy=='no-backup'))
2314
2315
2316 class cmd_file_id(Command):
2317@@ -1620,11 +1678,17 @@
2318
2319 _see_also = ['check']
2320 takes_args = ['branch?']
2321+ takes_options = [
2322+ Option('canonicalize-chks',
2323+ help='Make sure CHKs are in canonical form (repairs '
2324+ 'bug 522637).',
2325+ hidden=True),
2326+ ]
2327
2328- def run(self, branch="."):
2329+ def run(self, branch=".", canonicalize_chks=False):
2330 from bzrlib.reconcile import reconcile
2331 dir = bzrdir.BzrDir.open(branch)
2332- reconcile(dir)
2333+ reconcile(dir, canonicalize_chks=canonicalize_chks)
2334
2335
2336 class cmd_revision_history(Command):
2337@@ -1707,10 +1771,12 @@
2338 ),
2339 Option('append-revisions-only',
2340 help='Never change revnos or the existing log.'
2341- ' Append revisions to it only.')
2342+ ' Append revisions to it only.'),
2343+ Option('no-tree',
2344+ 'Create a branch without a working tree.')
2345 ]
2346 def run(self, location=None, format=None, append_revisions_only=False,
2347- create_prefix=False):
2348+ create_prefix=False, no_tree=False):
2349 if format is None:
2350 format = bzrdir.format_registry.make_bzrdir('default')
2351 if location is None:
2352@@ -1739,8 +1805,13 @@
2353 except errors.NotBranchError:
2354 # really a NotBzrDir error...
2355 create_branch = bzrdir.BzrDir.create_branch_convenience
2356+ if no_tree:
2357+ force_new_tree = False
2358+ else:
2359+ force_new_tree = None
2360 branch = create_branch(to_transport.base, format=format,
2361- possible_transports=[to_transport])
2362+ possible_transports=[to_transport],
2363+ force_new_tree=force_new_tree)
2364 a_bzrdir = branch.bzrdir
2365 else:
2366 from bzrlib.transport.local import LocalTransport
2367@@ -1750,7 +1821,8 @@
2368 raise errors.BranchExistsWithoutWorkingTree(location)
2369 raise errors.AlreadyBranchError(location)
2370 branch = a_bzrdir.create_branch()
2371- a_bzrdir.create_workingtree()
2372+ if not no_tree:
2373+ a_bzrdir.create_workingtree()
2374 if append_revisions_only:
2375 try:
2376 branch.set_append_revisions_only(True)
2377@@ -1850,6 +1922,13 @@
2378 "bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
2379 produces patches suitable for "patch -p1".
2380
2381+ Note that when using the -r argument with a range of revisions, the
2382+ differences are computed between the two specified revisions. That
2383+ is, the command does not show the changes introduced by the first
2384+ revision in the range. This differs from the interpretation of
2385+ revision ranges used by "bzr log" which includes the first revision
2386+ in the range.
2387+
2388 :Exit values:
2389 1 - changed
2390 2 - unrepresentable changes
2391@@ -1873,7 +1952,11 @@
2392
2393 bzr diff -r1..3 xxx
2394
2395- To see the changes introduced in revision X::
2396+ The changes introduced by revision 2 (equivalent to -r1..2)::
2397+
2398+ bzr diff -c2
2399+
2400+ To see the changes introduced by revision X::
2401
2402 bzr diff -cX
2403
2404@@ -1883,9 +1966,10 @@
2405
2406 bzr diff -r<chosen_parent>..X
2407
2408- The changes introduced by revision 2 (equivalent to -r1..2)::
2409+ The changes between the current revision and the previous revision
2410+ (equivalent to -c-1 and -r-2..-1)
2411
2412- bzr diff -c2
2413+ bzr diff -r-2..
2414
2415 Show just the differences for file NEWS::
2416
2417@@ -1906,6 +1990,10 @@
2418 Same as 'bzr diff' but prefix paths with old/ and new/::
2419
2420 bzr diff --prefix old/:new/
2421+
2422+ Show the differences using a custom diff program with options::
2423+
2424+ bzr diff --using /usr/bin/diff --diff-options -wu
2425 """
2426 _see_also = ['status']
2427 takes_args = ['file*']
2428@@ -1931,9 +2019,10 @@
2429 type=unicode,
2430 ),
2431 RegistryOption('format',
2432+ short_name='F',
2433 help='Diff format to use.',
2434 lazy_registry=('bzrlib.diff', 'format_registry'),
2435- value_switches=False, title='Diff format'),
2436+ title='Diff format'),
2437 ]
2438 aliases = ['di', 'dif']
2439 encoding_type = 'exact'
2440@@ -2020,7 +2109,9 @@
2441 @display_command
2442 def run(self, null=False, directory=u'.'):
2443 tree = WorkingTree.open_containing(directory)[0]
2444+ self.add_cleanup(tree.lock_read().unlock)
2445 td = tree.changes_from(tree.basis_tree())
2446+ self.cleanup_now()
2447 for path, id, kind, text_modified, meta_modified in td.modified:
2448 if null:
2449 self.outf.write(path + '\0')
2450@@ -2656,8 +2747,13 @@
2451 Patterns prefixed with '!!' act as regular ignore patterns, but have
2452 precedence over the '!' exception patterns.
2453
2454- Note: ignore patterns containing shell wildcards must be quoted from
2455- the shell on Unix.
2456+ :Notes:
2457+
2458+ * Ignore patterns containing shell wildcards must be quoted from
2459+ the shell on Unix.
2460+
2461+ * Ignore patterns starting with "#" act as comments in the ignore file.
2462+ To ignore patterns that begin with that character, use the "RE:" prefix.
2463
2464 :Examples:
2465 Ignore the top level Makefile::
2466@@ -2672,6 +2768,10 @@
2467
2468 bzr ignore "!special.class"
2469
2470+ Ignore files whose name begins with the "#" character::
2471+
2472+ bzr ignore "RE:^#"
2473+
2474 Ignore .o files under the lib directory::
2475
2476 bzr ignore "lib/**/*.o"
2477@@ -3117,7 +3217,7 @@
2478
2479 properties = {}
2480
2481- tree, selected_list = tree_files(selected_list)
2482+ tree, selected_list = WorkingTree.open_containing_paths(selected_list)
2483 if selected_list == ['']:
2484 # workaround - commit of root of tree should be exactly the same
2485 # as just default commit in that tree, and succeed even though
2486@@ -3158,9 +3258,9 @@
2487 def get_message(commit_obj):
2488 """Callback to get commit message"""
2489 if file:
2490- f = codecs.open(file, 'rt', osutils.get_user_encoding())
2491+ f = open(file)
2492 try:
2493- my_message = f.read()
2494+ my_message = f.read().decode(osutils.get_user_encoding())
2495 finally:
2496 f.close()
2497 elif message is not None:
2498@@ -3197,7 +3297,7 @@
2499 reporter=None, verbose=verbose, revprops=properties,
2500 authors=author, timestamp=commit_stamp,
2501 timezone=offset,
2502- exclude=safe_relpath_files(tree, exclude))
2503+ exclude=tree.safe_relpath_files(exclude))
2504 except PointlessCommit:
2505 raise errors.BzrCommandError("No changes to commit."
2506 " Use --unchanged to commit anyhow.")
2507@@ -3287,27 +3387,62 @@
2508
2509
2510 class cmd_upgrade(Command):
2511- __doc__ = """Upgrade branch storage to current format.
2512-
2513- The check command or bzr developers may sometimes advise you to run
2514- this command. When the default format has changed you may also be warned
2515- during other operations to upgrade.
2516+ __doc__ = """Upgrade a repository, branch or working tree to a newer format.
2517+
2518+ When the default format has changed after a major new release of
2519+ Bazaar, you may be informed during certain operations that you
2520+ should upgrade. Upgrading to a newer format may improve performance
2521+ or make new features available. It may however limit interoperability
2522+ with older repositories or with older versions of Bazaar.
2523+
2524+ If you wish to upgrade to a particular format rather than the
2525+ current default, that can be specified using the --format option.
2526+ As a consequence, you can use the upgrade command this way to
2527+ "downgrade" to an earlier format, though some conversions are
2528+ a one way process (e.g. changing from the 1.x default to the
2529+ 2.x default) so downgrading is not always possible.
2530+
2531+ A backup.bzr.~#~ directory is created at the start of the conversion
2532+ process (where # is a number). By default, this is left there on
2533+ completion. If the conversion fails, delete the new .bzr directory
2534+ and rename this one back in its place. Use the --clean option to ask
2535+ for the backup.bzr directory to be removed on successful conversion.
2536+ Alternatively, you can delete it by hand if everything looks good
2537+ afterwards.
2538+
2539+ If the location given is a shared repository, dependent branches
2540+ are also converted provided the repository converts successfully.
2541+ If the conversion of a branch fails, remaining branches are still
2542+ tried.
2543+
2544+ For more information on upgrades, see the Bazaar Upgrade Guide,
2545+ http://doc.bazaar.canonical.com/latest/en/upgrade-guide/.
2546 """
2547
2548- _see_also = ['check']
2549+ _see_also = ['check', 'reconcile', 'formats']
2550 takes_args = ['url?']
2551 takes_options = [
2552- RegistryOption('format',
2553- help='Upgrade to a specific format. See "bzr help'
2554- ' formats" for details.',
2555- lazy_registry=('bzrlib.bzrdir', 'format_registry'),
2556- converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
2557- value_switches=True, title='Branch format'),
2558- ]
2559+ RegistryOption('format',
2560+ help='Upgrade to a specific format. See "bzr help'
2561+ ' formats" for details.',
2562+ lazy_registry=('bzrlib.bzrdir', 'format_registry'),
2563+ converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
2564+ value_switches=True, title='Branch format'),
2565+ Option('clean',
2566+ help='Remove the backup.bzr directory if successful.'),
2567+ Option('dry-run',
2568+ help="Show what would be done, but don't actually do anything."),
2569+ ]
2570
2571- def run(self, url='.', format=None):
2572+ def run(self, url='.', format=None, clean=False, dry_run=False):
2573 from bzrlib.upgrade import upgrade
2574- upgrade(url, format)
2575+ exceptions = upgrade(url, format, clean_up=clean, dry_run=dry_run)
2576+ if exceptions:
2577+ if len(exceptions) == 1:
2578+ # Compatibility with historical behavior
2579+ raise exceptions[0]
2580+ else:
2581+ return 3
2582
2583
2584 class cmd_whoami(Command):
2585@@ -3340,7 +3475,7 @@
2586 try:
2587 c = Branch.open_containing(u'.')[0].get_config()
2588 except errors.NotBranchError:
2589- c = config.GlobalConfig()
2590+ c = _mod_config.GlobalConfig()
2591 else:
2592 c = Branch.open(directory).get_config()
2593 if email:
2594@@ -3349,9 +3484,13 @@
2595 self.outf.write(c.username() + '\n')
2596 return
2597
2598+ if email:
2599+ raise errors.BzrCommandError("--email can only be used to display existing "
2600+ "identity")
2601+
2602 # display a warning if an email address isn't included in the given name.
2603 try:
2604- config.extract_email_address(name)
2605+ _mod_config.extract_email_address(name)
2606 except errors.NoEmailInUsername, e:
2607 warning('"%s" does not seem to contain an email address. '
2608 'This is allowed, but not recommended.', name)
2609@@ -3363,7 +3502,7 @@
2610 else:
2611 c = Branch.open(directory).get_config()
2612 else:
2613- c = config.GlobalConfig()
2614+ c = _mod_config.GlobalConfig()
2615 c.set_user_option('email', name)
2616
2617
2618@@ -3436,13 +3575,13 @@
2619 'bzr alias --remove expects an alias to remove.')
2620 # If alias is not found, print something like:
2621 # unalias: foo: not found
2622- c = config.GlobalConfig()
2623+ c = _mod_config.GlobalConfig()
2624 c.unset_alias(alias_name)
2625
2626 @display_command
2627 def print_aliases(self):
2628 """Print out the defined aliases in a similar format to bash."""
2629- aliases = config.GlobalConfig().get_aliases()
2630+ aliases = _mod_config.GlobalConfig().get_aliases()
2631 for key, value in sorted(aliases.iteritems()):
2632 self.outf.write('bzr alias %s="%s"\n' % (key, value))
2633
2634@@ -3458,7 +3597,7 @@
2635
2636 def set_alias(self, alias_name, alias_command):
2637 """Save the alias in the global config."""
2638- c = config.GlobalConfig()
2639+ c = _mod_config.GlobalConfig()
2640 c.set_alias(alias_name, alias_command)
2641
2642
2643@@ -3499,6 +3638,9 @@
2644 If you set BZR_TEST_PDB=1 when running selftest, failing tests will drop
2645 into a pdb postmortem session.
2646
2647+ The --coverage=DIRNAME global option produces a report with covered code
2648+ indicated.
2649+
2650 :Examples:
2651 Run only tests relating to 'ignore'::
2652
2653@@ -3588,10 +3730,7 @@
2654 randomize=None, exclude=None, strict=False,
2655 load_list=None, debugflag=None, starting_with=None, subunit=False,
2656 parallel=None, lsprof_tests=False):
2657- from bzrlib.tests import selftest
2658-
2659- # Make deprecation warnings visible, unless -Werror is set
2660- symbol_versioning.activate_deprecation_warnings(override=False)
2661+ from bzrlib import tests
2662
2663 if testspecs_list is not None:
2664 pattern = '|'.join(testspecs_list)
2665@@ -3638,7 +3777,14 @@
2666 "starting_with": starting_with
2667 }
2668 selftest_kwargs.update(self.additional_selftest_args)
2669- result = selftest(**selftest_kwargs)
2670+
2671+ # Make deprecation warnings visible, unless -Werror is set
2672+ cleanup = symbol_versioning.activate_deprecation_warnings(
2673+ override=False)
2674+ try:
2675+ result = tests.selftest(**selftest_kwargs)
2676+ finally:
2677+ cleanup()
2678 return int(not result)
2679
2680
2681@@ -3701,16 +3847,20 @@
2682 with bzr send. If neither is specified, the default is the upstream branch
2683 or the branch most recently merged using --remember.
2684
2685- When merging a branch, by default the tip will be merged. To pick a different
2686- revision, pass --revision. If you specify two values, the first will be used as
2687- BASE and the second one as OTHER. Merging individual revisions, or a subset of
2688- available revisions, like this is commonly referred to as "cherrypicking".
2689-
2690- Revision numbers are always relative to the branch being merged.
2691-
2692- By default, bzr will try to merge in all new work from the other
2693- branch, automatically determining an appropriate base. If this
2694- fails, you may need to give an explicit base.
2695+ When merging from a branch, by default bzr will try to merge in all new
2696+ work from the other branch, automatically determining an appropriate base
2697+ revision. If this fails, you may need to give an explicit base.
2698+
2699+ To pick a different ending revision, pass "--revision OTHER". bzr will
2700+ try to merge in all new work up to and including revision OTHER.
2701+
2702+ If you specify two values, "--revision BASE..OTHER", only revisions BASE
2703+ through OTHER, excluding BASE but including OTHER, will be merged. If this
2704+ causes some revisions to be skipped, i.e. if the destination branch does
2705+ not already contain revision BASE, such a merge is commonly referred to as
2706+ a "cherrypick".
2707+
2708+ Revision numbers are always relative to the source branch.
2709
2710 Merge will do its best to combine the changes in two branches, but there
2711 are some kinds of problems only a human can fix. When it encounters those,
2712@@ -3740,7 +3890,7 @@
2713 you to apply each diff hunk and file change, similar to "shelve".
2714
2715 :Examples:
2716- To merge the latest revision from bzr.dev::
2717+ To merge all new revisions from bzr.dev::
2718
2719 bzr merge ../bzr.dev
2720
2721@@ -3980,7 +4130,9 @@
2722 if ((remember or tree.branch.get_submit_branch() is None) and
2723 user_location is not None):
2724 tree.branch.set_submit_branch(other_branch.base)
2725- _merge_tags_if_possible(other_branch, tree.branch)
2726+ # Merge tags (but don't set them in the master branch yet, the user
2727+ # might revert this merge). Commit will propagate them.
2728+ _merge_tags_if_possible(other_branch, tree.branch, ignore_master=True)
2729 merger = _mod_merge.Merger.from_revision_ids(pb, tree,
2730 other_revision_id, base_revision_id, other_branch, base_branch)
2731 if other_path != '':
2732@@ -4087,7 +4239,7 @@
2733 from bzrlib.conflicts import restore
2734 if merge_type is None:
2735 merge_type = _mod_merge.Merge3Merger
2736- tree, file_list = tree_files(file_list)
2737+ tree, file_list = WorkingTree.open_containing_paths(file_list)
2738 self.add_cleanup(tree.lock_write().unlock)
2739 parents = tree.get_parent_ids()
2740 if len(parents) != 2:
2741@@ -4154,9 +4306,10 @@
2742 last committed revision is used.
2743
2744 To remove only some changes, without reverting to a prior version, use
2745- merge instead. For example, "merge . --revision -2..-3" will remove the
2746- changes introduced by -2, without affecting the changes introduced by -1.
2747- Or to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
2748+ merge instead. For example, "merge . -r -2..-3" (don't forget the ".")
2749+ will remove the changes introduced by the second last commit (-2), without
2750+ affecting the changes introduced by the last commit (-1). To remove
2751+ certain changes on a hunk-by-hunk basis, see the shelve command.
2752
2753 By default, any files that have been manually changed will be backed up
2754 first. (Files changed only by merge are not backed up.) Backup files have
2755@@ -4192,7 +4345,7 @@
2756 target branches.
2757 """
2758
2759- _see_also = ['cat', 'export']
2760+ _see_also = ['cat', 'export', 'merge', 'shelve']
2761 takes_options = [
2762 'revision',
2763 Option('no-backup', "Do not save backups of reverted files."),
2764@@ -4203,7 +4356,7 @@
2765
2766 def run(self, revision=None, no_backup=False, file_list=None,
2767 forget_merges=None):
2768- tree, file_list = tree_files(file_list)
2769+ tree, file_list = WorkingTree.open_containing_paths(file_list)
2770 self.add_cleanup(tree.lock_tree_write().unlock)
2771 if forget_merges:
2772 tree.set_parent_ids(tree.get_parent_ids()[:1])
2773@@ -4491,26 +4644,9 @@
2774
2775 @display_command
2776 def run(self, verbose=False):
2777- import bzrlib.plugin
2778- from inspect import getdoc
2779- result = []
2780- for name, plugin in bzrlib.plugin.plugins().items():
2781- version = plugin.__version__
2782- if version == 'unknown':
2783- version = ''
2784- name_ver = '%s %s' % (name, version)
2785- d = getdoc(plugin.module)
2786- if d:
2787- doc = d.split('\n')[0]
2788- else:
2789- doc = '(no description)'
2790- result.append((name_ver, doc, plugin.path()))
2791- for name_ver, doc, path in sorted(result):
2792- self.outf.write("%s\n" % name_ver)
2793- self.outf.write(" %s\n" % doc)
2794- if verbose:
2795- self.outf.write(" %s\n" % path)
2796- self.outf.write("\n")
2797+ from bzrlib import plugin
2798+ self.outf.writelines(
2799+ plugin.describe_plugins(show_paths=verbose))
2800
2801
2802 class cmd_testament(Command):
2803@@ -4812,8 +4948,11 @@
2804 self.outf.write('The above revision(s) will be removed.\n')
2805
2806 if not force:
2807- if not ui.ui_factory.get_boolean('Are you sure'):
2808- self.outf.write('Canceled')
2809+ if not ui.ui_factory.confirm_action(
2810+ 'Uncommit these revisions',
2811+ 'bzrlib.builtins.uncommit',
2812+ {}):
2813+ self.outf.write('Canceled\n')
2814 return 0
2815
2816 mutter('Uncommitting from {%s} to {%s}',
2817@@ -4825,7 +4964,10 @@
2818
2819
2820 class cmd_break_lock(Command):
2821- __doc__ = """Break a dead lock on a repository, branch or working directory.
2822+ __doc__ = """Break a dead lock.
2823+
2824+ This command breaks a lock on a repository, branch, working directory or
2825+ config file.
2826
2827 CAUTION: Locks should only be broken when you are sure that the process
2828 holding the lock has been stopped.
2829@@ -4836,17 +4978,33 @@
2830 :Examples:
2831 bzr break-lock
2832 bzr break-lock bzr+ssh://example.com/bzr/foo
2833+ bzr break-lock --conf ~/.bazaar
2834 """
2835+
2836 takes_args = ['location?']
2837+ takes_options = [
2838+ Option('config',
2839+ help='LOCATION is the directory where the config lock is.'),
2840+ Option('force',
2841+ help='Do not ask for confirmation before breaking the lock.'),
2842+ ]
2843
2844- def run(self, location=None, show=False):
2845+ def run(self, location=None, config=False, force=False):
2846 if location is None:
2847 location = u'.'
2848- control, relpath = bzrdir.BzrDir.open_containing(location)
2849- try:
2850- control.break_lock()
2851- except NotImplementedError:
2852- pass
2853+ if force:
2854+ ui.ui_factory = ui.ConfirmationUserInterfacePolicy(ui.ui_factory,
2855+ None,
2856+ {'bzrlib.lockdir.break': True})
2857+ if config:
2858+ conf = _mod_config.LockableConfig(file_name=location)
2859+ conf.break_lock()
2860+ else:
2861+ control, relpath = bzrdir.BzrDir.open_containing(location)
2862+ try:
2863+ control.break_lock()
2864+ except NotImplementedError:
2865+ pass
2866
2867
2868 class cmd_wait_until_signalled(Command):
2869@@ -4937,7 +5095,7 @@
2870 not part of it. (Such trees can be produced by "bzr split", but also by
2871 running "bzr branch" with the target inside a tree.)
2872
2873- The result is a combined tree, with the subtree no longer an independant
2874+ The result is a combined tree, with the subtree no longer an independent
2875 part. This is marked as a merge of the subtree into the containing tree,
2876 and all history is preserved.
2877 """
2878@@ -5339,7 +5497,7 @@
2879 if tag_name is None:
2880 raise errors.BzrCommandError("No tag specified to delete.")
2881 branch.tags.delete_tag(tag_name)
2882- self.outf.write('Deleted tag %s.\n' % tag_name)
2883+ note('Deleted tag %s.' % tag_name)
2884 else:
2885 if revision:
2886 if len(revision) != 1:
2887@@ -5357,7 +5515,7 @@
2888 if (not force) and branch.tags.has_tag(tag_name):
2889 raise errors.TagAlreadyExists(tag_name)
2890 branch.tags.set_tag(tag_name, revision_id)
2891- self.outf.write('Created tag %s.\n' % tag_name)
2892+ note('Created tag %s.' % tag_name)
2893
2894
2895 class cmd_tags(Command):
2896@@ -5370,22 +5528,17 @@
2897 takes_options = [
2898 custom_help('directory',
2899 help='Branch whose tags should be displayed.'),
2900- RegistryOption.from_kwargs('sort',
2901+ RegistryOption('sort',
2902 'Sort tags by different criteria.', title='Sorting',
2903- alpha='Sort tags lexicographically (default).',
2904- time='Sort tags chronologically.',
2905+ lazy_registry=('bzrlib.tag', 'tag_sort_methods')
2906 ),
2907 'show-ids',
2908 'revision',
2909 ]
2910
2911 @display_command
2912- def run(self,
2913- directory='.',
2914- sort='alpha',
2915- show_ids=False,
2916- revision=None,
2917- ):
2918+ def run(self, directory='.', sort=None, show_ids=False, revision=None):
2919+ from bzrlib.tag import tag_sort_methods
2920 branch, relpath = Branch.open_containing(directory)
2921
2922 tags = branch.tags.get_tag_dict().items()
2923@@ -5400,19 +5553,9 @@
2924 # only show revisions between revid1 and revid2 (inclusive)
2925 tags = [(tag, revid) for tag, revid in tags if
2926 graph.is_between(revid, revid1, revid2)]
2927- if sort == 'alpha':
2928- tags.sort()
2929- elif sort == 'time':
2930- timestamps = {}
2931- for tag, revid in tags:
2932- try:
2933- revobj = branch.repository.get_revision(revid)
2934- except errors.NoSuchRevision:
2935- timestamp = sys.maxint # place them at the end
2936- else:
2937- timestamp = revobj.timestamp
2938- timestamps[revid] = timestamp
2939- tags.sort(key=lambda x: timestamps[x[1]])
2940+ if sort is None:
2941+ sort = tag_sort_methods.get()
2942+ sort(branch, tags)
2943 if not show_ids:
2944 # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
2945 for index, (tag, revid) in enumerate(tags):
2946@@ -5705,7 +5848,8 @@
2947 name=None,
2948 switch=None,
2949 ):
2950- tree, file_list = tree_files(file_list, apply_view=False)
2951+ tree, file_list = WorkingTree.open_containing_paths(file_list,
2952+ apply_view=False)
2953 current_view, view_dict = tree.views.get_view_info()
2954 if name is None:
2955 name = current_view
2956@@ -5815,7 +5959,7 @@
2957 location = "."
2958 branch = Branch.open_containing(location)[0]
2959 branch.bzrdir.destroy_branch()
2960-
2961+
2962
2963 class cmd_shelve(Command):
2964 __doc__ = """Temporarily set aside some changes from the current tree.
2965@@ -5840,6 +5984,18 @@
2966
2967 You can put multiple items on the shelf, and by default, 'unshelve' will
2968 restore the most recently shelved changes.
2969+
2970+ For complicated changes, it is possible to edit the changes in a separate
2971+ editor program to decide what the file remaining in the working copy
2972+ should look like. To do this, add the configuration option
2973+
2974+ change_editor = PROGRAM @new_path @old_path
2975+
2976+ where @new_path is replaced with the path of the new version of the
2977+ file and @old_path is replaced with the path of the old version of
2978+ the file. The PROGRAM should save the new file with the desired
2979+ contents of the file in the working tree.
2980+
2981 """
2982
2983 takes_args = ['file*']
2984@@ -5857,12 +6013,12 @@
2985 Option('destroy',
2986 help='Destroy removed changes instead of shelving them.'),
2987 ]
2988- _see_also = ['unshelve']
2989+ _see_also = ['unshelve', 'configuration']
2990
2991 def run(self, revision=None, all=False, file_list=None, message=None,
2992- writer=None, list=False, destroy=False, directory=u'.'):
2993+ writer=None, list=False, destroy=False, directory=None):
2994 if list:
2995- return self.run_for_list()
2996+ return self.run_for_list(directory=directory)
2997 from bzrlib.shelf_ui import Shelver
2998 if writer is None:
2999 writer = bzrlib.option.diff_writer_registry.get()
3000@@ -5876,8 +6032,10 @@
3001 except errors.UserAbort:
3002 return 0
3003
3004- def run_for_list(self):
3005- tree = WorkingTree.open_containing('.')[0]
3006+ def run_for_list(self, directory=None):
3007+ if directory is None:
3008+ directory = u'.'
3009+ tree = WorkingTree.open_containing(directory)[0]
3010 self.add_cleanup(tree.lock_read().unlock)
3011 manager = tree.get_shelf_manager()
3012 shelves = manager.active_shelves()
3013@@ -6012,10 +6170,12 @@
3014 # be only called once.
3015 for (name, aliases, module_name) in [
3016 ('cmd_bundle_info', [], 'bzrlib.bundle.commands'),
3017+ ('cmd_config', [], 'bzrlib.config'),
3018 ('cmd_dpush', [], 'bzrlib.foreign'),
3019 ('cmd_version_info', [], 'bzrlib.cmd_version_info'),
3020 ('cmd_resolve', ['resolved'], 'bzrlib.conflicts'),
3021 ('cmd_conflicts', [], 'bzrlib.conflicts'),
3022 ('cmd_sign_my_commits', [], 'bzrlib.sign_my_commits'),
3023+ ('cmd_test_script', [], 'bzrlib.cmd_test_script'),
3024 ]:
3025 builtin_command_registry.register_lazy(name, aliases, module_name)
3026
3027=== modified file 'bzrlib/bundle/__init__.py'
3028--- bzrlib/bundle/__init__.py 2010-02-17 17:11:16 +0000
3029+++ bzrlib/bundle/__init__.py 2011-02-09 08:08:20 +0000
3030@@ -16,35 +16,26 @@
3031
3032 from cStringIO import StringIO
3033
3034-from bzrlib.symbol_versioning import deprecated_function, deprecated_in
3035 from bzrlib.lazy_import import lazy_import
3036 lazy_import(globals(), """
3037 from bzrlib import (
3038 errors,
3039+ transport as _mod_transport,
3040 urlutils,
3041 )
3042 from bzrlib.bundle import serializer as _serializer
3043 from bzrlib.merge_directive import MergeDirective
3044-from bzrlib.transport import (
3045- do_catching_redirections,
3046- get_transport,
3047- )
3048 """)
3049 from bzrlib.trace import note
3050
3051
3052-@deprecated_function(deprecated_in((1, 12, 0)))
3053-def read_bundle_from_url(url):
3054- return read_mergeable_from_url(url, _do_directive=False)
3055-
3056-
3057 def read_mergeable_from_url(url, _do_directive=True, possible_transports=None):
3058 """Read mergable object from a given URL.
3059
3060 :return: An object supporting get_target_revision. Raises NotABundle if
3061 the target is not a mergeable type.
3062 """
3063- child_transport = get_transport(url,
3064+ child_transport = _mod_transport.get_transport(url,
3065 possible_transports=possible_transports)
3066 transport = child_transport.clone('..')
3067 filename = transport.relpath(child_transport.base)
3068@@ -63,11 +54,11 @@
3069 exclude_trailing_slash=False)
3070 if not filename:
3071 raise errors.NotABundle('A directory cannot be a bundle')
3072- return get_transport(url)
3073+ return _mod_transport.get_transport(url)
3074
3075 try:
3076- bytef, transport = do_catching_redirections(get_bundle, transport,
3077- redirected_transport)
3078+ bytef, transport = _mod_transport.do_catching_redirections(
3079+ get_bundle, transport, redirected_transport)
3080 except errors.TooManyRedirections:
3081 raise errors.NotABundle(transport.clone(filename).base)
3082 except (errors.ConnectionReset, errors.ConnectionError), e:
3083
3084=== modified file 'bzrlib/bundle/bundle_data.py'
3085--- bzrlib/bundle/bundle_data.py 2010-06-16 12:47:51 +0000
3086+++ bzrlib/bundle/bundle_data.py 2011-02-09 08:08:20 +0000
3087@@ -289,7 +289,7 @@
3088 def _validate_revision(self, inventory, revision_id):
3089 """Make sure all revision entries match their checksum."""
3090
3091- # This is a mapping from each revision id to it's sha hash
3092+ # This is a mapping from each revision id to its sha hash
3093 rev_to_sha1 = {}
3094
3095 rev = self.get_revision(revision_id)
3096@@ -715,12 +715,11 @@
3097 ie.symlink_target = self.get_symlink_target(file_id)
3098 ie.revision = revision_id
3099
3100- if kind in ('directory', 'symlink'):
3101- ie.text_size, ie.text_sha1 = None, None
3102- else:
3103+ if kind == 'file':
3104 ie.text_size, ie.text_sha1 = self.get_size_and_sha1(file_id)
3105- if (ie.text_size is None) and (kind == 'file'):
3106- raise BzrError('Got a text_size of None for file_id %r' % file_id)
3107+ if ie.text_size is None:
3108+ raise BzrError(
3109+ 'Got a text_size of None for file_id %r' % file_id)
3110 inv.add(ie)
3111
3112 sorted_entries = self.sorted_path_id()
3113
3114=== modified file 'bzrlib/bundle/serializer/__init__.py'
3115--- bzrlib/bundle/serializer/__init__.py 2009-03-23 14:59:43 +0000
3116+++ bzrlib/bundle/serializer/__init__.py 2011-02-09 08:08:20 +0000
3117@@ -1,4 +1,4 @@
3118-# Copyright (C) 2005, 2006 Canonical Ltd
3119+# Copyright (C) 2005, 2006, 2007, 2009, 2010 Canonical Ltd
3120 #
3121 # This program is free software; you can redistribute it and/or modify
3122 # it under the terms of the GNU General Public License as published by
3123@@ -21,7 +21,10 @@
3124 from StringIO import StringIO
3125 import re
3126
3127-import bzrlib.errors as errors
3128+from bzrlib import (
3129+ errors,
3130+ pyutils,
3131+ )
3132 from bzrlib.diff import internal_diff
3133 from bzrlib.revision import NULL_REVISION
3134 # For backwards-compatibility
3135@@ -151,17 +154,6 @@
3136 """
3137 raise NotImplementedError
3138
3139- def write(self, source, revision_ids, forced_bases, f):
3140- """Write the bundle to the supplied file.
3141-
3142- DEPRECATED: see write_bundle
3143- :param source: A source for revision information
3144- :param revision_ids: The list of revision ids to serialize
3145- :param forced_bases: A dict of revision -> base that overrides default
3146- :param f: The file to output to
3147- """
3148- raise NotImplementedError
3149-
3150 def _write_bundle(self, repository, revision_id, base_revision_id, out):
3151 """Helper function for translating write_bundle to write"""
3152 forced_bases = {revision_id:base_revision_id}
3153@@ -202,8 +194,7 @@
3154 :param overwrite: Should this version override a default
3155 """
3156 def _loader(version):
3157- mod = __import__(module, globals(), locals(), [classname])
3158- klass = getattr(mod, classname)
3159+ klass = pyutils.get_named_object(module, classname)
3160 return klass(version)
3161 register(version, _loader, overwrite=overwrite)
3162
3163
3164=== modified file 'bzrlib/bundle/serializer/v4.py'
3165--- bzrlib/bundle/serializer/v4.py 2009-08-04 14:08:32 +0000
3166+++ bzrlib/bundle/serializer/v4.py 2011-02-09 08:08:20 +0000
3167@@ -1,4 +1,4 @@
3168-# Copyright (C) 2007 Canonical Ltd
3169+# Copyright (C) 2007-2010 Canonical Ltd
3170 #
3171 # This program is free software; you can redistribute it and/or modify
3172 # it under the terms of the GNU General Public License as published by
3173@@ -30,11 +30,49 @@
3174 serializer,
3175 trace,
3176 ui,
3177+ versionedfile as _mod_versionedfile,
3178 )
3179 from bzrlib.bundle import bundle_data, serializer as bundle_serializer
3180 from bzrlib import bencode
3181
3182
3183+class _MPDiffInventoryGenerator(_mod_versionedfile._MPDiffGenerator):
3184+ """Generate Inventory diffs serialized inventories."""
3185+
3186+ def __init__(self, repo, inventory_keys):
3187+ super(_MPDiffInventoryGenerator, self).__init__(repo.inventories,
3188+ inventory_keys)
3189+ self.repo = repo
3190+ self.sha1s = {}
3191+
3192+ def iter_diffs(self):
3193+ """Compute the diffs one at a time."""
3194+ # This is instead of compute_diffs() since we guarantee our ordering of
3195+ # inventories, we don't have to do any buffering
3196+ self._find_needed_keys()
3197+ # We actually use a slightly different ordering. We grab all of the
3198+ # parents first, and then grab the ordered requests.
3199+ needed_ids = [k[-1] for k in self.present_parents]
3200+ needed_ids.extend([k[-1] for k in self.ordered_keys])
3201+ inv_to_str = self.repo._serializer.write_inventory_to_string
3202+ for inv in self.repo.iter_inventories(needed_ids):
3203+ revision_id = inv.revision_id
3204+ key = (revision_id,)
3205+ if key in self.present_parents:
3206+ # Not a key we will transmit, which is a shame, since because
3207+ # of that bundles don't work with stacked branches
3208+ parent_ids = None
3209+ else:
3210+ parent_ids = [k[-1] for k in self.parent_map[key]]
3211+ as_bytes = inv_to_str(inv)
3212+ self._process_one_record(key, (as_bytes,))
3213+ if parent_ids is None:
3214+ continue
3215+ diff = self.diffs.pop(key)
3216+ sha1 = osutils.sha_string(as_bytes)
3217+ yield revision_id, parent_ids, sha1, diff
3218+
3219+
3220 class BundleWriter(object):
3221 """Writer for bundle-format files.
3222
3223@@ -348,48 +386,10 @@
3224 the other side.
3225 """
3226 inventory_key_order = [(r,) for r in revision_order]
3227- parent_map = self.repository.inventories.get_parent_map(
3228- inventory_key_order)
3229- missing_keys = set(inventory_key_order).difference(parent_map)
3230- if missing_keys:
3231- raise errors.RevisionNotPresent(list(missing_keys)[0],
3232- self.repository.inventories)
3233- inv_to_str = self.repository._serializer.write_inventory_to_string
3234- # Make sure that we grab the parent texts first
3235- just_parents = set()
3236- map(just_parents.update, parent_map.itervalues())
3237- just_parents.difference_update(parent_map)
3238- # Ignore ghost parents
3239- present_parents = self.repository.inventories.get_parent_map(
3240- just_parents)
3241- ghost_keys = just_parents.difference(present_parents)
3242- needed_inventories = list(present_parents) + inventory_key_order
3243- needed_inventories = [k[-1] for k in needed_inventories]
3244- all_lines = {}
3245- for inv in self.repository.iter_inventories(needed_inventories):
3246- revision_id = inv.revision_id
3247- key = (revision_id,)
3248- as_bytes = inv_to_str(inv)
3249- # The sha1 is validated as the xml/textual form, not as the
3250- # form-in-the-repository
3251- sha1 = osutils.sha_string(as_bytes)
3252- as_lines = osutils.split_lines(as_bytes)
3253- del as_bytes
3254- all_lines[key] = as_lines
3255- if key in just_parents:
3256- # We don't transmit those entries
3257- continue
3258- # Create an mpdiff for this text, and add it to the output
3259- parent_keys = parent_map[key]
3260- # See the comment in VF.make_mpdiffs about how this effects
3261- # ordering when there are ghosts present. I think we have a latent
3262- # bug
3263- parent_lines = [all_lines[p_key] for p_key in parent_keys
3264- if p_key not in ghost_keys]
3265- diff = multiparent.MultiParent.from_lines(
3266- as_lines, parent_lines)
3267+ generator = _MPDiffInventoryGenerator(self.repository,
3268+ inventory_key_order)
3269+ for revision_id, parent_ids, sha1, diff in generator.iter_diffs():
3270 text = ''.join(diff.to_patch())
3271- parent_ids = [k[-1] for k in parent_keys]
3272 self.bundle.add_multiparent_record(text, sha1, parent_ids,
3273 'inventory', revision_id, None)
3274
3275
3276=== modified file 'bzrlib/bzrdir.py'
3277--- bzrlib/bzrdir.py 2010-11-26 18:13:30 +0000
3278+++ bzrlib/bzrdir.py 2011-02-09 08:08:20 +0000
3279@@ -1,4 +1,4 @@
3280-# Copyright (C) 2006-2010 Canonical Ltd
3281+# Copyright (C) 2006-2011 Canonical Ltd
3282 #
3283 # This program is free software; you can redistribute it and/or modify
3284 # it under the terms of the GNU General Public License as published by
3285@@ -34,20 +34,22 @@
3286 from bzrlib.lazy_import import lazy_import
3287 lazy_import(globals(), """
3288 from stat import S_ISDIR
3289-import textwrap
3290
3291 import bzrlib
3292 from bzrlib import (
3293 branch,
3294 config,
3295+ controldir,
3296 errors,
3297 graph,
3298 lockable_files,
3299 lockdir,
3300 osutils,
3301+ pyutils,
3302 remote,
3303 repository,
3304 revision as _mod_revision,
3305+ transport as _mod_transport,
3306 ui,
3307 urlutils,
3308 versionedfile,
3309@@ -65,14 +67,16 @@
3310 )
3311 from bzrlib.repofmt import pack_repo
3312 from bzrlib.smart.client import _SmartClient
3313-from bzrlib.store.versioned import WeaveStore
3314+from bzrlib.store.versioned import VersionedFileStore
3315 from bzrlib.transactions import WriteTransaction
3316 from bzrlib.transport import (
3317 do_catching_redirections,
3318- get_transport,
3319 local,
3320 )
3321-from bzrlib.weave import Weave
3322+from bzrlib.weave import (
3323+ WeaveFile,
3324+ Weave,
3325+ )
3326 """)
3327
3328 from bzrlib.trace import (
3329@@ -86,42 +90,13 @@
3330 registry,
3331 symbol_versioning,
3332 )
3333-
3334-
3335-class ControlComponent(object):
3336- """Abstract base class for control directory components.
3337-
3338- This provides interfaces that are common across bzrdirs,
3339- repositories, branches, and workingtree control directories.
3340-
3341- They all expose two urls and transports: the *user* URL is the
3342- one that stops above the control directory (eg .bzr) and that
3343- should normally be used in messages, and the *control* URL is
3344- under that in eg .bzr/checkout and is used to read the control
3345- files.
3346-
3347- This can be used as a mixin and is intended to fit with
3348- foreign formats.
3349- """
3350-
3351- @property
3352- def control_transport(self):
3353- raise NotImplementedError
3354-
3355- @property
3356- def control_url(self):
3357- return self.control_transport.base
3358-
3359- @property
3360- def user_transport(self):
3361- raise NotImplementedError
3362-
3363- @property
3364- def user_url(self):
3365- return self.user_transport.base
3366-
3367-
3368-class BzrDir(ControlComponent):
3369+from bzrlib.symbol_versioning import (
3370+ deprecated_in,
3371+ deprecated_method,
3372+ )
3373+
3374+
3375+class BzrDir(controldir.ControlDir):
3376 """A .bzr control diretory.
3377
3378 BzrDir instances let you create or open any of the things that can be
3379@@ -158,10 +133,6 @@
3380 return
3381 thing_to_unlock.break_lock()
3382
3383- def can_convert_format(self):
3384- """Return true if this bzrdir is one whose format we can convert from."""
3385- return True
3386-
3387 def check_conversion_target(self, target_format):
3388 """Check that a bzrdir as a whole can be converted to a new format."""
3389 # The only current restriction is that the repository content can be
3390@@ -202,28 +173,9 @@
3391 format.get_format_description(),
3392 basedir)
3393
3394- def clone(self, url, revision_id=None, force_new_repo=False,
3395- preserve_stacking=False):
3396- """Clone this bzrdir and its contents to url verbatim.
3397-
3398- :param url: The url create the clone at. If url's last component does
3399- not exist, it will be created.
3400- :param revision_id: The tip revision-id to use for any branch or
3401- working tree. If not None, then the clone operation may tune
3402- itself to download less data.
3403- :param force_new_repo: Do not use a shared repository for the target
3404- even if one is available.
3405- :param preserve_stacking: When cloning a stacked branch, stack the
3406- new branch on top of the other branch's stacked-on branch.
3407- """
3408- return self.clone_on_transport(get_transport(url),
3409- revision_id=revision_id,
3410- force_new_repo=force_new_repo,
3411- preserve_stacking=preserve_stacking)
3412-
3413 def clone_on_transport(self, transport, revision_id=None,
3414 force_new_repo=False, preserve_stacking=False, stacked_on=None,
3415- create_prefix=False, use_existing_dir=True):
3416+ create_prefix=False, use_existing_dir=True, no_tree=False):
3417 """Clone this bzrdir and its contents to transport verbatim.
3418
3419 :param transport: The transport for the location to produce the clone
3420@@ -241,12 +193,12 @@
3421 """
3422 # Overview: put together a broad description of what we want to end up
3423 # with; then make as few api calls as possible to do it.
3424-
3425+
3426 # We may want to create a repo/branch/tree, if we do so what format
3427 # would we want for each:
3428 require_stacking = (stacked_on is not None)
3429 format = self.cloning_metadir(require_stacking)
3430-
3431+
3432 # Figure out what objects we want:
3433 try:
3434 local_repo = self.find_repository()
3435@@ -271,7 +223,7 @@
3436 # we should look up the policy needs first, or just use it as a hint,
3437 # or something.
3438 if local_repo:
3439- make_working_trees = local_repo.make_working_trees()
3440+ make_working_trees = local_repo.make_working_trees() and not no_tree
3441 want_shared = local_repo.is_shared()
3442 repo_format_name = format.repository_format.network_name()
3443 else:
3444@@ -326,26 +278,8 @@
3445 # TODO: This should be given a Transport, and should chdir up; otherwise
3446 # this will open a new connection.
3447 def _make_tail(self, url):
3448- t = get_transport(url)
3449- t.ensure_base()
3450-
3451- @classmethod
3452- def create(cls, base, format=None, possible_transports=None):
3453- """Create a new BzrDir at the url 'base'.
3454-
3455- :param format: If supplied, the format of branch to create. If not
3456- supplied, the default is used.
3457- :param possible_transports: If supplied, a list of transports that
3458- can be reused to share a remote connection.
3459- """
3460- if cls is not BzrDir:
3461- raise AssertionError("BzrDir.create always creates the default"
3462- " format, not one of %r" % cls)
3463- t = get_transport(base, possible_transports)
3464- t.ensure_base()
3465- if format is None:
3466- format = BzrDirFormat.get_default_format()
3467- return format.initialize_on_transport(t)
3468+ t = _mod_transport.get_transport(url)
3469+ t.ensure_base()
3470
3471 @staticmethod
3472 def find_bzrdirs(transport, evaluate=None, list_current=None):
3473@@ -388,15 +322,6 @@
3474 for subdir in sorted(subdirs, reverse=True):
3475 pending.append(current_transport.clone(subdir))
3476
3477- def list_branches(self):
3478- """Return a sequence of all branches local to this control directory.
3479-
3480- """
3481- try:
3482- return [self.open_branch()]
3483- except (errors.NotBranchError, errors.NoRepositoryPresent):
3484- return []
3485-
3486 @staticmethod
3487 def find_branches(transport):
3488 """Find all branches under a transport.
3489@@ -425,29 +350,6 @@
3490 ret.extend(branches)
3491 return ret
3492
3493- def destroy_repository(self):
3494- """Destroy the repository in this BzrDir"""
3495- raise NotImplementedError(self.destroy_repository)
3496-
3497- def create_branch(self, name=None):
3498- """Create a branch in this BzrDir.
3499-
3500- :param name: Name of the colocated branch to create, None for
3501- the default branch.
3502-
3503- The bzrdir's format will control what branch format is created.
3504- For more control see BranchFormatXX.create(a_bzrdir).
3505- """
3506- raise NotImplementedError(self.create_branch)
3507-
3508- def destroy_branch(self, name=None):
3509- """Destroy a branch in this BzrDir.
3510-
3511- :param name: Name of the branch to destroy, None for the default
3512- branch.
3513- """
3514- raise NotImplementedError(self.destroy_branch)
3515-
3516 @staticmethod
3517 def create_branch_and_repo(base, force_new_repo=False, format=None):
3518 """Create a new BzrDir, Branch and Repository at the url 'base'.
3519@@ -566,7 +468,7 @@
3520 """
3521 if force_new_tree:
3522 # check for non local urls
3523- t = get_transport(base, possible_transports)
3524+ t = _mod_transport.get_transport(base, possible_transports)
3525 if not isinstance(t, local.LocalTransport):
3526 raise errors.NotLocalUrl(base)
3527 bzrdir = BzrDir.create(base, format, possible_transports)
3528@@ -594,7 +496,7 @@
3529 :param format: Override for the bzrdir format to create.
3530 :return: The WorkingTree object.
3531 """
3532- t = get_transport(base)
3533+ t = _mod_transport.get_transport(base)
3534 if not isinstance(t, local.LocalTransport):
3535 raise errors.NotLocalUrl(base)
3536 bzrdir = BzrDir.create_branch_and_repo(base,
3537@@ -602,42 +504,30 @@
3538 format=format).bzrdir
3539 return bzrdir.create_workingtree()
3540
3541- def create_workingtree(self, revision_id=None, from_branch=None,
3542- accelerator_tree=None, hardlink=False):
3543- """Create a working tree at this BzrDir.
3544-
3545- :param revision_id: create it as of this revision id.
3546- :param from_branch: override bzrdir branch (for lightweight checkouts)
3547- :param accelerator_tree: A tree which can be used for retrieving file
3548- contents more quickly than the revision tree, i.e. a workingtree.
3549- The revision tree will be used for cases where accelerator_tree's
3550- content is different.
3551+ @deprecated_method(deprecated_in((2, 3, 0)))
3552+ def generate_backup_name(self, base):
3553+ return self._available_backup_name(base)
3554+
3555+ def _available_backup_name(self, base):
3556+ """Find a non-existing backup file name based on base.
3557+
3558+ See bzrlib.osutils.available_backup_name about race conditions.
3559 """
3560- raise NotImplementedError(self.create_workingtree)
3561+ return osutils.available_backup_name(base, self.root_transport.has)
3562
3563 def backup_bzrdir(self):
3564 """Backup this bzr control directory.
3565
3566 :return: Tuple with old path name and new path name
3567 """
3568- def name_gen(base='backup.bzr'):
3569- counter = 1
3570- name = "%s.~%d~" % (base, counter)
3571- while self.root_transport.has(name):
3572- counter += 1
3573- name = "%s.~%d~" % (base, counter)
3574- return name
3575
3576- backup_dir=name_gen()
3577 pb = ui.ui_factory.nested_progress_bar()
3578 try:
3579- # FIXME: bug 300001 -- the backup fails if the backup directory
3580- # already exists, but it should instead either remove it or make
3581- # a new backup directory.
3582- #
3583 old_path = self.root_transport.abspath('.bzr')
3584+ backup_dir = self._available_backup_name('backup.bzr')
3585 new_path = self.root_transport.abspath(backup_dir)
3586- ui.ui_factory.note('making backup of %s\n to %s' % (old_path, new_path,))
3587+ ui.ui_factory.note('making backup of %s\n to %s'
3588+ % (old_path, new_path,))
3589 self.root_transport.copy_tree('.bzr', backup_dir)
3590 return (old_path, new_path)
3591 finally:
3592@@ -668,21 +558,6 @@
3593 else:
3594 pass
3595
3596- def destroy_workingtree(self):
3597- """Destroy the working tree at this BzrDir.
3598-
3599- Formats that do not support this may raise UnsupportedOperation.
3600- """
3601- raise NotImplementedError(self.destroy_workingtree)
3602-
3603- def destroy_workingtree_metadata(self):
3604- """Destroy the control files for the working tree at this BzrDir.
3605-
3606- The contents of working tree files are not affected.
3607- Formats that do not support this may raise UnsupportedOperation.
3608- """
3609- raise NotImplementedError(self.destroy_workingtree_metadata)
3610-
3611 def _find_containing(self, evaluate):
3612 """Find something in a containing control directory.
3613
3614@@ -737,33 +612,6 @@
3615 raise errors.NoRepositoryPresent(self)
3616 return found_repo
3617
3618- def get_branch_reference(self, name=None):
3619- """Return the referenced URL for the branch in this bzrdir.
3620-
3621- :param name: Optional colocated branch name
3622- :raises NotBranchError: If there is no Branch.
3623- :raises NoColocatedBranchSupport: If a branch name was specified
3624- but colocated branches are not supported.
3625- :return: The URL the branch in this bzrdir references if it is a
3626- reference branch, or None for regular branches.
3627- """
3628- if name is not None:
3629- raise errors.NoColocatedBranchSupport(self)
3630- return None
3631-
3632- def get_branch_transport(self, branch_format, name=None):
3633- """Get the transport for use by branch format in this BzrDir.
3634-
3635- Note that bzr dirs that do not support format strings will raise
3636- IncompatibleFormat if the branch format they are given has
3637- a format string, and vice versa.
3638-
3639- If branch_format is None, the transport is returned with no
3640- checking. If it is not None, then the returned transport is
3641- guaranteed to point to an existing directory ready for use.
3642- """
3643- raise NotImplementedError(self.get_branch_transport)
3644-
3645 def _find_creation_modes(self):
3646 """Determine the appropriate modes for files and directories.
3647
3648@@ -808,32 +656,6 @@
3649 self._find_creation_modes()
3650 return self._dir_mode
3651
3652- def get_repository_transport(self, repository_format):
3653- """Get the transport for use by repository format in this BzrDir.
3654-
3655- Note that bzr dirs that do not support format strings will raise
3656- IncompatibleFormat if the repository format they are given has
3657- a format string, and vice versa.
3658-
3659- If repository_format is None, the transport is returned with no
3660- checking. If it is not None, then the returned transport is
3661- guaranteed to point to an existing directory ready for use.
3662- """
3663- raise NotImplementedError(self.get_repository_transport)
3664-
3665- def get_workingtree_transport(self, tree_format):
3666- """Get the transport for use by workingtree format in this BzrDir.
3667-
3668- Note that bzr dirs that do not support format strings will raise
3669- IncompatibleFormat if the workingtree format they are given has a
3670- format string, and vice versa.
3671-
3672- If workingtree_format is None, the transport is returned with no
3673- checking. If it is not None, then the returned transport is
3674- guaranteed to point to an existing directory ready for use.
3675- """
3676- raise NotImplementedError(self.get_workingtree_transport)
3677-
3678 def get_config(self):
3679 """Get configuration for this BzrDir."""
3680 return config.BzrDirConfig(self)
3681@@ -857,11 +679,11 @@
3682 self.transport = _transport.clone('.bzr')
3683 self.root_transport = _transport
3684 self._mode_check_done = False
3685-
3686+
3687 @property
3688 def user_transport(self):
3689 return self.root_transport
3690-
3691+
3692 @property
3693 def control_transport(self):
3694 return self.transport
3695@@ -873,9 +695,7 @@
3696
3697 This is true IF and ONLY IF the filename is part of the namespace reserved
3698 for bzr control dirs. Currently this is the '.bzr' directory in the root
3699- of the root_transport. it is expected that plugins will need to extend
3700- this in the future - for instance to make bzr talk with svn working
3701- trees.
3702+ of the root_transport.
3703 """
3704 # this might be better on the BzrDirFormat class because it refers to
3705 # all the possible bzrdir disk formats.
3706@@ -885,17 +705,6 @@
3707 # add new tests for it to the appropriate place.
3708 return filename == '.bzr' or filename.startswith('.bzr/')
3709
3710- def needs_format_conversion(self, format=None):
3711- """Return true if this bzrdir needs convert_format run on it.
3712-
3713- For instance, if the repository format is out of date but the
3714- branch and working tree are not, this should return True.
3715-
3716- :param format: Optional parameter indicating a specific desired
3717- format we plan to arrive at.
3718- """
3719- raise NotImplementedError(self.needs_format_conversion)
3720-
3721 @staticmethod
3722 def open_unsupported(base):
3723 """Open a branch which is not supported."""
3724@@ -907,7 +716,7 @@
3725
3726 :param _unsupported: a private parameter to the BzrDir class.
3727 """
3728- t = get_transport(base, possible_transports=possible_transports)
3729+ t = _mod_transport.get_transport(base, possible_transports)
3730 return BzrDir.open_from_transport(t, _unsupported=_unsupported)
3731
3732 @staticmethod
3733@@ -924,7 +733,7 @@
3734 # the redirections.
3735 base = transport.base
3736 def find_format(transport):
3737- return transport, BzrDirFormat.find_format(
3738+ return transport, controldir.ControlDirFormat.find_format(
3739 transport, _server_formats=_server_formats)
3740
3741 def redirected(transport, e, redirection_notice):
3742@@ -945,17 +754,6 @@
3743 BzrDir._check_supported(format, _unsupported)
3744 return format.open(transport, _found=True)
3745
3746- def open_branch(self, name=None, unsupported=False,
3747- ignore_fallbacks=False):
3748- """Open the branch object at this BzrDir if one is present.
3749-
3750- If unsupported is True, then no longer supported branch formats can
3751- still be opened.
3752-
3753- TODO: static convenience version of this?
3754- """
3755- raise NotImplementedError(self.open_branch)
3756-
3757 @staticmethod
3758 def open_containing(url, possible_transports=None):
3759 """Open an existing branch which contains url.
3760@@ -963,7 +761,7 @@
3761 :param url: url to search from.
3762 See open_containing_from_transport for more detail.
3763 """
3764- transport = get_transport(url, possible_transports)
3765+ transport = _mod_transport.get_transport(url, possible_transports)
3766 return BzrDir.open_containing_from_transport(transport)
3767
3768 @staticmethod
3769@@ -999,27 +797,6 @@
3770 raise errors.NotBranchError(path=url)
3771 a_transport = new_t
3772
3773- def _get_tree_branch(self, name=None):
3774- """Return the branch and tree, if any, for this bzrdir.
3775-
3776- :param name: Name of colocated branch to open.
3777-
3778- Return None for tree if not present or inaccessible.
3779- Raise NotBranchError if no branch is present.
3780- :return: (tree, branch)
3781- """
3782- try:
3783- tree = self.open_workingtree()
3784- except (errors.NoWorkingTree, errors.NotLocalUrl):
3785- tree = None
3786- branch = self.open_branch(name=name)
3787- else:
3788- if name is not None:
3789- branch = self.open_branch(name=name)
3790- else:
3791- branch = tree.branch
3792- return tree, branch
3793-
3794 @classmethod
3795 def open_tree_or_branch(klass, location):
3796 """Return the branch and working tree at a location.
3797@@ -1071,59 +848,6 @@
3798 raise errors.NotBranchError(location)
3799 return tree, branch, branch.repository, relpath
3800
3801- def open_repository(self, _unsupported=False):
3802- """Open the repository object at this BzrDir if one is present.
3803-
3804- This will not follow the Branch object pointer - it's strictly a direct
3805- open facility. Most client code should use open_branch().repository to
3806- get at a repository.
3807-
3808- :param _unsupported: a private parameter, not part of the api.
3809- TODO: static convenience version of this?
3810- """
3811- raise NotImplementedError(self.open_repository)
3812-
3813- def open_workingtree(self, _unsupported=False,
3814- recommend_upgrade=True, from_branch=None):
3815- """Open the workingtree object at this BzrDir if one is present.
3816-
3817- :param recommend_upgrade: Optional keyword parameter, when True (the
3818- default), emit through the ui module a recommendation that the user
3819- upgrade the working tree when the workingtree being opened is old
3820- (but still fully supported).
3821- :param from_branch: override bzrdir branch (for lightweight checkouts)
3822- """
3823- raise NotImplementedError(self.open_workingtree)
3824-
3825- def has_branch(self, name=None):
3826- """Tell if this bzrdir contains a branch.
3827-
3828- Note: if you're going to open the branch, you should just go ahead
3829- and try, and not ask permission first. (This method just opens the
3830- branch and discards it, and that's somewhat expensive.)
3831- """
3832- try:
3833- self.open_branch(name)
3834- return True
3835- except errors.NotBranchError:
3836- return False
3837-
3838- def has_workingtree(self):
3839- """Tell if this bzrdir contains a working tree.
3840-
3841- This will still raise an exception if the bzrdir has a workingtree that
3842- is remote & inaccessible.
3843-
3844- Note: if you're going to open the working tree, you should just go ahead
3845- and try, and not ask permission first. (This method just opens the
3846- workingtree and discards it, and that's somewhat expensive.)
3847- """
3848- try:
3849- self.open_workingtree(recommend_upgrade=False)
3850- return True
3851- except errors.NoWorkingTree:
3852- return False
3853-
3854 def _cloning_metadir(self):
3855 """Produce a metadir suitable for cloning with.
3856
3857@@ -1187,192 +911,23 @@
3858 format.require_stacking()
3859 return format
3860
3861- def checkout_metadir(self):
3862- return self.cloning_metadir()
3863-
3864- def sprout(self, url, revision_id=None, force_new_repo=False,
3865- recurse='down', possible_transports=None,
3866- accelerator_tree=None, hardlink=False, stacked=False,
3867- source_branch=None, create_tree_if_local=True):
3868- """Create a copy of this bzrdir prepared for use as a new line of
3869- development.
3870-
3871- If url's last component does not exist, it will be created.
3872-
3873- Attributes related to the identity of the source branch like
3874- branch nickname will be cleaned, a working tree is created
3875- whether one existed before or not; and a local branch is always
3876- created.
3877-
3878- if revision_id is not None, then the clone operation may tune
3879- itself to download less data.
3880- :param accelerator_tree: A tree which can be used for retrieving file
3881- contents more quickly than the revision tree, i.e. a workingtree.
3882- The revision tree will be used for cases where accelerator_tree's
3883- content is different.
3884- :param hardlink: If true, hard-link files from accelerator_tree,
3885- where possible.
3886- :param stacked: If true, create a stacked branch referring to the
3887- location of this control directory.
3888- :param create_tree_if_local: If true, a working-tree will be created
3889- when working locally.
3890+ @classmethod
3891+ def create(cls, base, format=None, possible_transports=None):
3892+ """Create a new BzrDir at the url 'base'.
3893+
3894+ :param format: If supplied, the format of branch to create. If not
3895+ supplied, the default is used.
3896+ :param possible_transports: If supplied, a list of transports that
3897+ can be reused to share a remote connection.
3898 """
3899- target_transport = get_transport(url, possible_transports)
3900- target_transport.ensure_base()
3901- cloning_format = self.cloning_metadir(stacked)
3902- # Create/update the result branch
3903- result = cloning_format.initialize_on_transport(target_transport)
3904- # if a stacked branch wasn't requested, we don't create one
3905- # even if the origin was stacked
3906- stacked_branch_url = None
3907- if source_branch is not None:
3908- if stacked:
3909- stacked_branch_url = self.root_transport.base
3910- source_repository = source_branch.repository
3911- else:
3912- try:
3913- source_branch = self.open_branch()
3914- source_repository = source_branch.repository
3915- if stacked:
3916- stacked_branch_url = self.root_transport.base
3917- except errors.NotBranchError:
3918- source_branch = None
3919- try:
3920- source_repository = self.open_repository()
3921- except errors.NoRepositoryPresent:
3922- source_repository = None
3923- repository_policy = result.determine_repository_policy(
3924- force_new_repo, stacked_branch_url, require_stacking=stacked)
3925- result_repo, is_new_repo = repository_policy.acquire_repository()
3926- is_stacked = stacked or (len(result_repo._fallback_repositories) != 0)
3927- if is_new_repo and revision_id is not None and not is_stacked:
3928- fetch_spec = graph.PendingAncestryResult(
3929- [revision_id], source_repository)
3930- else:
3931- fetch_spec = None
3932- if source_repository is not None:
3933- # Fetch while stacked to prevent unstacked fetch from
3934- # Branch.sprout.
3935- if fetch_spec is None:
3936- result_repo.fetch(source_repository, revision_id=revision_id)
3937- else:
3938- result_repo.fetch(source_repository, fetch_spec=fetch_spec)
3939-
3940- if source_branch is None:
3941- # this is for sprouting a bzrdir without a branch; is that
3942- # actually useful?
3943- # Not especially, but it's part of the contract.
3944- result_branch = result.create_branch()
3945- else:
3946- result_branch = source_branch.sprout(result,
3947- revision_id=revision_id, repository_policy=repository_policy)
3948- mutter("created new branch %r" % (result_branch,))
3949-
3950- # Create/update the result working tree
3951- if (create_tree_if_local and
3952- isinstance(target_transport, local.LocalTransport) and
3953- (result_repo is None or result_repo.make_working_trees())):
3954- wt = result.create_workingtree(accelerator_tree=accelerator_tree,
3955- hardlink=hardlink)
3956- wt.lock_write()
3957- try:
3958- if wt.path2id('') is None:
3959- try:
3960- wt.set_root_id(self.open_workingtree.get_root_id())
3961- except errors.NoWorkingTree:
3962- pass
3963- finally:
3964- wt.unlock()
3965- else:
3966- wt = None
3967- if recurse == 'down':
3968- if wt is not None:
3969- basis = wt.basis_tree()
3970- basis.lock_read()
3971- subtrees = basis.iter_references()
3972- elif result_branch is not None:
3973- basis = result_branch.basis_tree()
3974- basis.lock_read()
3975- subtrees = basis.iter_references()
3976- elif source_branch is not None:
3977- basis = source_branch.basis_tree()
3978- basis.lock_read()
3979- subtrees = basis.iter_references()
3980- else:
3981- subtrees = []
3982- basis = None
3983- try:
3984- for path, file_id in subtrees:
3985- target = urlutils.join(url, urlutils.escape(path))
3986- sublocation = source_branch.reference_parent(file_id, path)
3987- sublocation.bzrdir.sprout(target,
3988- basis.get_reference_revision(file_id, path),
3989- force_new_repo=force_new_repo, recurse=recurse,
3990- stacked=stacked)
3991- finally:
3992- if basis is not None:
3993- basis.unlock()
3994- return result
3995-
3996- def push_branch(self, source, revision_id=None, overwrite=False,
3997- remember=False, create_prefix=False):
3998- """Push the source branch into this BzrDir."""
3999- br_to = None
4000- # If we can open a branch, use its direct repository, otherwise see
4001- # if there is a repository without a branch.
4002- try:
4003- br_to = self.open_branch()
4004- except errors.NotBranchError:
4005- # Didn't find a branch, can we find a repository?
4006- repository_to = self.find_repository()
4007- else:
4008- # Found a branch, so we must have found a repository
4009- repository_to = br_to.repository
4010-
4011- push_result = PushResult()
4012- push_result.source_branch = source
4013- if br_to is None:
4014- # We have a repository but no branch, copy the revisions, and then
4015- # create a branch.
4016- repository_to.fetch(source.repository, revision_id=revision_id)
4017- br_to = source.clone(self, revision_id=revision_id)
4018- if source.get_push_location() is None or remember:
4019- source.set_push_location(br_to.base)
4020- push_result.stacked_on = None
4021- push_result.branch_push_result = None
4022- push_result.old_revno = None
4023- push_result.old_revid = _mod_revision.NULL_REVISION
4024- push_result.target_branch = br_to
4025- push_result.master_branch = None
4026- push_result.workingtree_updated = False
4027- else:
4028- # We have successfully opened the branch, remember if necessary:
4029- if source.get_push_location() is None or remember:
4030- source.set_push_location(br_to.base)
4031- try:
4032- tree_to = self.open_workingtree()
4033- except errors.NotLocalUrl:
4034- push_result.branch_push_result = source.push(br_to,
4035- overwrite, stop_revision=revision_id)
4036- push_result.workingtree_updated = False
4037- except errors.NoWorkingTree:
4038- push_result.branch_push_result = source.push(br_to,
4039- overwrite, stop_revision=revision_id)
4040- push_result.workingtree_updated = None # Not applicable
4041- else:
4042- tree_to.lock_write()
4043- try:
4044- push_result.branch_push_result = source.push(
4045- tree_to.branch, overwrite, stop_revision=revision_id)
4046- tree_to.update()
4047- finally:
4048- tree_to.unlock()
4049- push_result.workingtree_updated = True
4050- push_result.old_revno = push_result.branch_push_result.old_revno
4051- push_result.old_revid = push_result.branch_push_result.old_revid
4052- push_result.target_branch = \
4053- push_result.branch_push_result.target_branch
4054- return push_result
4055+ if cls is not BzrDir:
4056+ raise AssertionError("BzrDir.create always creates the"
4057+ "default format, not one of %r" % cls)
4058+ t = _mod_transport.get_transport(base, possible_transports)
4059+ t.ensure_base()
4060+ if format is None:
4061+ format = controldir.ControlDirFormat.get_default_format()
4062+ return format.initialize_on_transport(t)
4063
4064
4065 class BzrDirHooks(hooks.Hooks):
4066@@ -1448,7 +1003,7 @@
4067 def cloning_metadir(self, require_stacking=False):
4068 """Produce a metadir suitable for cloning with."""
4069 if require_stacking:
4070- return format_registry.make_bzrdir('1.6')
4071+ return controldir.format_registry.make_bzrdir('1.6')
4072 return self._format.__class__()
4073
4074 def clone(self, url, revision_id=None, force_new_repo=False,
4075@@ -1474,8 +1029,11 @@
4076 tree.clone(result)
4077 return result
4078
4079- def create_branch(self, name=None):
4080+ def create_branch(self, name=None, repository=None):
4081 """See BzrDir.create_branch."""
4082+ if repository is not None:
4083+ raise NotImplementedError(
4084+ "create_branch(repository=<not None>) on %r" % (self,))
4085 return self._format.get_branch_format().initialize(self, name=name)
4086
4087 def destroy_branch(self, name=None):
4088@@ -1711,9 +1269,10 @@
4089 """See BzrDir.can_convert_format()."""
4090 return True
4091
4092- def create_branch(self, name=None):
4093+ def create_branch(self, name=None, repository=None):
4094 """See BzrDir.create_branch."""
4095- return self._format.get_branch_format().initialize(self, name=name)
4096+ return self._format.get_branch_format().initialize(self, name=name,
4097+ repository=repository)
4098
4099 def destroy_branch(self, name=None):
4100 """See BzrDir.create_branch."""
4101@@ -1741,7 +1300,10 @@
4102 wt = self.open_workingtree(recommend_upgrade=False)
4103 repository = wt.branch.repository
4104 empty = repository.revision_tree(_mod_revision.NULL_REVISION)
4105- wt.revert(old_tree=empty)
4106+ # We ignore the conflicts returned by wt.revert since we're about to
4107+ # delete the wt metadata anyway, all that should be left here are
4108+ # detritus. But see bug #634470 about subtree .bzr dirs.
4109+ conflicts = wt.revert(old_tree=empty)
4110 self.destroy_workingtree_metadata()
4111
4112 def destroy_workingtree_metadata(self):
4113@@ -1891,13 +1453,66 @@
4114 return config.TransportConfig(self.transport, 'control.conf')
4115
4116
4117-class BzrDirFormat(object):
4118- """An encapsulation of the initialization and open routines for a format.
4119-
4120- Formats provide three things:
4121- * An initialization routine,
4122- * a format string,
4123- * an open routine.
4124+class BzrProber(controldir.Prober):
4125+ """Prober for formats that use a .bzr/ control directory."""
4126+
4127+ _formats = {}
4128+ """The known .bzr formats."""
4129+
4130+ @classmethod
4131+ def register_bzrdir_format(klass, format):
4132+ klass._formats[format.get_format_string()] = format
4133+
4134+ @classmethod
4135+ def unregister_bzrdir_format(klass, format):
4136+ del klass._formats[format.get_format_string()]
4137+
4138+ @classmethod
4139+ def probe_transport(klass, transport):
4140+ """Return the .bzrdir style format present in a directory."""
4141+ try:
4142+ format_string = transport.get_bytes(".bzr/branch-format")
4143+ except errors.NoSuchFile:
4144+ raise errors.NotBranchError(path=transport.base)
4145+ try:
4146+ return klass._formats[format_string]
4147+ except KeyError:
4148+ raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
4149+
4150+
4151+controldir.ControlDirFormat.register_prober(BzrProber)
4152+
4153+
4154+class RemoteBzrProber(controldir.Prober):
4155+ """Prober for remote servers that provide a Bazaar smart server."""
4156+
4157+ @classmethod
4158+ def probe_transport(klass, transport):
4159+ """Return a RemoteBzrDirFormat object if it looks possible."""
4160+ try:
4161+ medium = transport.get_smart_medium()
4162+ except (NotImplementedError, AttributeError,
4163+ errors.TransportNotPossible, errors.NoSmartMedium,
4164+ errors.SmartProtocolError):
4165+ # no smart server, so not a branch for this format type.
4166+ raise errors.NotBranchError(path=transport.base)
4167+ else:
4168+ # Decline to open it if the server doesn't support our required
4169+ # version (3) so that the VFS-based transport will do it.
4170+ if medium.should_probe():
4171+ try:
4172+ server_version = medium.protocol_version()
4173+ except errors.SmartProtocolError:
4174+ # Apparently there's no usable smart server there, even though
4175+ # the medium supports the smart protocol.
4176+ raise errors.NotBranchError(path=transport.base)
4177+ if server_version != '2':
4178+ raise errors.NotBranchError(path=transport.base)
4179+ return RemoteBzrDirFormat()
4180+
4181+
4182+class BzrDirFormat(controldir.ControlDirFormat):
4183+ """ControlDirFormat base class for .bzr/ directories.
4184
4185 Formats are placed in a dict by their format string for reference
4186 during bzrdir opening. These should be subclasses of BzrDirFormat
4187@@ -1906,104 +1521,17 @@
4188 Once a format is deprecated, just deprecate the initialize and open
4189 methods on the format class. Do not deprecate the object, as the
4190 object will be created every system load.
4191-
4192- :cvar colocated_branches: Whether this formats supports colocated branches.
4193- """
4194-
4195- _default_format = None
4196- """The default format used for new .bzr dirs."""
4197-
4198- _formats = {}
4199- """The known formats."""
4200-
4201- _control_formats = []
4202- """The registered control formats - .bzr, ....
4203-
4204- This is a list of BzrDirFormat objects.
4205- """
4206-
4207- _control_server_formats = []
4208- """The registered control server formats, e.g. RemoteBzrDirs.
4209-
4210- This is a list of BzrDirFormat objects.
4211 """
4212
4213 _lock_file_name = 'branch-lock'
4214
4215- colocated_branches = False
4216- """Whether co-located branches are supported for this control dir format.
4217- """
4218-
4219 # _lock_class must be set in subclasses to the lock type, typ.
4220 # TransportLock or LockDir
4221
4222- @classmethod
4223- def find_format(klass, transport, _server_formats=True):
4224- """Return the format present at transport."""
4225- if _server_formats:
4226- formats = klass._control_server_formats + klass._control_formats
4227- else:
4228- formats = klass._control_formats
4229- for format in formats:
4230- try:
4231- return format.probe_transport(transport)
4232- except errors.NotBranchError:
4233- # this format does not find a control dir here.
4234- pass
4235- raise errors.NotBranchError(path=transport.base)
4236-
4237- @classmethod
4238- def probe_transport(klass, transport):
4239- """Return the .bzrdir style format present in a directory."""
4240- try:
4241- format_string = transport.get_bytes(".bzr/branch-format")
4242- except errors.NoSuchFile:
4243- raise errors.NotBranchError(path=transport.base)
4244- try:
4245- return klass._formats[format_string]
4246- except KeyError:
4247- raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
4248-
4249- @classmethod
4250- def get_default_format(klass):
4251- """Return the current default format."""
4252- return klass._default_format
4253-
4254 def get_format_string(self):
4255 """Return the ASCII format string that identifies this format."""
4256 raise NotImplementedError(self.get_format_string)
4257
4258- def get_format_description(self):
4259- """Return the short description for this format."""
4260- raise NotImplementedError(self.get_format_description)
4261-
4262- def get_converter(self, format=None):
4263- """Return the converter to use to convert bzrdirs needing converts.
4264-
4265- This returns a bzrlib.bzrdir.Converter object.
4266-
4267- This should return the best upgrader to step this format towards the
4268- current default format. In the case of plugins we can/should provide
4269- some means for them to extend the range of returnable converters.
4270-
4271- :param format: Optional format to override the default format of the
4272- library.
4273- """
4274- raise NotImplementedError(self.get_converter)
4275-
4276- def initialize(self, url, possible_transports=None):
4277- """Create a bzr control dir at this url and return an opened copy.
4278-
4279- While not deprecated, this method is very specific and its use will
4280- lead to many round trips to setup a working environment. See
4281- initialize_on_transport_ex for a [nearly] all-in-one method.
4282-
4283- Subclasses should typically override initialize_on_transport
4284- instead of this method.
4285- """
4286- return self.initialize_on_transport(get_transport(url,
4287- possible_transports))
4288-
4289 def initialize_on_transport(self, transport):
4290 """Initialize a new bzrdir in the base directory of a Transport."""
4291 try:
4292@@ -2141,7 +1669,7 @@
4293 utf8_files = [('README',
4294 "This is a Bazaar control directory.\n"
4295 "Do not change any files in this directory.\n"
4296- "See http://bazaar-vcs.org/ for more information about Bazaar.\n"),
4297+ "See http://bazaar.canonical.com/ for more information about Bazaar.\n"),
4298 ('branch-format', self.get_format_string()),
4299 ]
4300 # NB: no need to escape relative paths that are url safe.
4301@@ -2157,55 +1685,13 @@
4302 control_files.unlock()
4303 return self.open(transport, _found=True)
4304
4305- def is_supported(self):
4306- """Is this format supported?
4307-
4308- Supported formats must be initializable and openable.
4309- Unsupported formats may not support initialization or committing or
4310- some other features depending on the reason for not being supported.
4311- """
4312- return True
4313-
4314- def network_name(self):
4315- """A simple byte string uniquely identifying this format for RPC calls.
4316-
4317- Bzr control formats use thir disk format string to identify the format
4318- over the wire. Its possible that other control formats have more
4319- complex detection requirements, so we permit them to use any unique and
4320- immutable string they desire.
4321- """
4322- raise NotImplementedError(self.network_name)
4323-
4324- def same_model(self, target_format):
4325- return (self.repository_format.rich_root_data ==
4326- target_format.rich_root_data)
4327-
4328- @classmethod
4329- def known_formats(klass):
4330- """Return all the known formats.
4331-
4332- Concrete formats should override _known_formats.
4333- """
4334- # There is double indirection here to make sure that control
4335- # formats used by more than one dir format will only be probed
4336- # once. This can otherwise be quite expensive for remote connections.
4337- result = set()
4338- for format in klass._control_formats:
4339- result.update(format._known_formats())
4340- return result
4341-
4342- @classmethod
4343- def _known_formats(klass):
4344- """Return the known format instances for this control format."""
4345- return set(klass._formats.values())
4346-
4347 def open(self, transport, _found=False):
4348 """Return an instance of this format for the dir transport points at.
4349
4350 _found is a private parameter, do not use it.
4351 """
4352 if not _found:
4353- found_format = BzrDirFormat.find_format(transport)
4354+ found_format = controldir.ControlDirFormat.find_format(transport)
4355 if not isinstance(found_format, self.__class__):
4356 raise AssertionError("%s was asked to open %s, but it seems to need "
4357 "format %s"
4358@@ -2225,40 +1711,10 @@
4359
4360 @classmethod
4361 def register_format(klass, format):
4362- klass._formats[format.get_format_string()] = format
4363+ BzrProber.register_bzrdir_format(format)
4364 # bzr native formats have a network name of their format string.
4365- network_format_registry.register(format.get_format_string(), format.__class__)
4366-
4367- @classmethod
4368- def register_control_format(klass, format):
4369- """Register a format that does not use '.bzr' for its control dir.
4370-
4371- TODO: This should be pulled up into a 'ControlDirFormat' base class
4372- which BzrDirFormat can inherit from, and renamed to register_format
4373- there. It has been done without that for now for simplicity of
4374- implementation.
4375- """
4376- klass._control_formats.append(format)
4377-
4378- @classmethod
4379- def register_control_server_format(klass, format):
4380- """Register a control format for client-server environments.
4381-
4382- These formats will be tried before ones registered with
4383- register_control_format. This gives implementations that decide to the
4384- chance to grab it before anything looks at the contents of the format
4385- file.
4386- """
4387- klass._control_server_formats.append(format)
4388-
4389- @classmethod
4390- def _set_default_format(klass, format):
4391- """Set default format (for testing behavior of defaults only)"""
4392- klass._default_format = format
4393-
4394- def __str__(self):
4395- # Trim the newline
4396- return self.get_format_description().rstrip()
4397+ controldir.network_format_registry.register(format.get_format_string(), format.__class__)
4398+ controldir.ControlDirFormat.register_format(format)
4399
4400 def _supply_sub_formats_to(self, other_format):
4401 """Give other_format the same values for sub formats as this has.
4402@@ -2274,11 +1730,9 @@
4403
4404 @classmethod
4405 def unregister_format(klass, format):
4406- del klass._formats[format.get_format_string()]
4407-
4408- @classmethod
4409- def unregister_control_format(klass, format):
4410- klass._control_formats.remove(format)
4411+ BzrProber.unregister_bzrdir_format(format)
4412+ controldir.ControlDirFormat.unregister_format(format)
4413+ controldir.network_format_registry.remove(format.get_format_string())
4414
4415
4416 class BzrDirFormat4(BzrDirFormat):
4417@@ -2392,7 +1846,8 @@
4418 return ConvertBzrDir5To6()
4419
4420 def _initialize_for_clone(self, url):
4421- return self.initialize_on_transport(get_transport(url), _cloning=True)
4422+ return self.initialize_on_transport(
4423+ _mod_transport.get_transport(url), _cloning=True)
4424
4425 def initialize_on_transport(self, transport, _cloning=False):
4426 """Format 5 dirs always have working tree, branch and repository.
4427@@ -2452,7 +1907,8 @@
4428 return ConvertBzrDir6ToMeta()
4429
4430 def _initialize_for_clone(self, url):
4431- return self.initialize_on_transport(get_transport(url), _cloning=True)
4432+ return self.initialize_on_transport(
4433+ _mod_transport.get_transport(url), _cloning=True)
4434
4435 def initialize_on_transport(self, transport, _cloning=False):
4436 """Format 6 dirs always have working tree, branch and repository.
4437@@ -2687,25 +2143,13 @@
4438 __set_workingtree_format)
4439
4440
4441-network_format_registry = registry.FormatRegistry()
4442-"""Registry of formats indexed by their network name.
4443-
4444-The network name for a BzrDirFormat is an identifier that can be used when
4445-referring to formats with smart server operations. See
4446-BzrDirFormat.network_name() for more detail.
4447-"""
4448-
4449-
4450-# Register bzr control format
4451-BzrDirFormat.register_control_format(BzrDirFormat)
4452-
4453 # Register bzr formats
4454 BzrDirFormat.register_format(BzrDirFormat4())
4455 BzrDirFormat.register_format(BzrDirFormat5())
4456 BzrDirFormat.register_format(BzrDirFormat6())
4457 __default_format = BzrDirMetaFormat1()
4458 BzrDirFormat.register_format(__default_format)
4459-BzrDirFormat._default_format = __default_format
4460+controldir.ControlDirFormat._default_format = __default_format
4461
4462
4463 class Converter(object):
4464@@ -2813,9 +2257,11 @@
4465 mode=self.bzrdir._get_file_mode())
4466
4467 def _write_all_weaves(self):
4468- controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
4469+ controlweaves = VersionedFileStore(self.bzrdir.transport, prefixed=False,
4470+ versionedfile_class=WeaveFile)
4471 weave_transport = self.bzrdir.transport.clone('weaves')
4472- weaves = WeaveStore(weave_transport, prefixed=False)
4473+ weaves = VersionedFileStore(weave_transport, prefixed=False,
4474+ versionedfile_class=WeaveFile)
4475 transaction = WriteTransaction()
4476
4477 try:
4478@@ -2939,7 +2385,6 @@
4479 previous_entries = dict((head, parent_candiate_entries[head]) for head
4480 in heads)
4481 self.snapshot_ie(previous_entries, ie, w, rev_id)
4482- del ie.text_id
4483
4484 def get_parent_map(self, revision_ids):
4485 """See graph.StackedParentsProvider.get_parent_map"""
4486@@ -3247,6 +2692,8 @@
4487 class RemoteBzrDirFormat(BzrDirMetaFormat1):
4488 """Format representing bzrdirs accessed via a smart server"""
4489
4490+ supports_workingtrees = False
4491+
4492 def __init__(self):
4493 BzrDirMetaFormat1.__init__(self)
4494 # XXX: It's a bit ugly that the network name is here, because we'd
4495@@ -3261,7 +2708,7 @@
4496
4497 def get_format_description(self):
4498 if self._network_name:
4499- real_format = network_format_registry.get(self._network_name)
4500+ real_format = controldir.network_format_registry.get(self._network_name)
4501 return 'Remote: ' + real_format.get_format_description()
4502 return 'bzr remote bzrdir'
4503
4504@@ -3274,30 +2721,6 @@
4505 else:
4506 raise AssertionError("No network name set.")
4507
4508- @classmethod
4509- def probe_transport(klass, transport):
4510- """Return a RemoteBzrDirFormat object if it looks possible."""
4511- try:
4512- medium = transport.get_smart_medium()
4513- except (NotImplementedError, AttributeError,
4514- errors.TransportNotPossible, errors.NoSmartMedium,
4515- errors.SmartProtocolError):
4516- # no smart server, so not a branch for this format type.
4517- raise errors.NotBranchError(path=transport.base)
4518- else:
4519- # Decline to open it if the server doesn't support our required
4520- # version (3) so that the VFS-based transport will do it.
4521- if medium.should_probe():
4522- try:
4523- server_version = medium.protocol_version()
4524- except errors.SmartProtocolError:
4525- # Apparently there's no usable smart server there, even though
4526- # the medium supports the smart protocol.
4527- raise errors.NotBranchError(path=transport.base)
4528- if server_version != '2':
4529- raise errors.NotBranchError(path=transport.base)
4530- return klass()
4531-
4532 def initialize_on_transport(self, transport):
4533 try:
4534 # hand off the request to the smart server
4535@@ -3502,190 +2925,7 @@
4536 BzrDirMetaFormat1._set_repository_format) #.im_func)
4537
4538
4539-BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
4540-
4541-
4542-class BzrDirFormatInfo(object):
4543-
4544- def __init__(self, native, deprecated, hidden, experimental):
4545- self.deprecated = deprecated
4546- self.native = native
4547- self.hidden = hidden
4548- self.experimental = experimental
4549-
4550-
4551-class BzrDirFormatRegistry(registry.Registry):
4552- """Registry of user-selectable BzrDir subformats.
4553-
4554- Differs from BzrDirFormat._control_formats in that it provides sub-formats,
4555- e.g. BzrDirMeta1 with weave repository. Also, it's more user-oriented.
4556- """
4557-
4558- def __init__(self):
4559- """Create a BzrDirFormatRegistry."""
4560- self._aliases = set()
4561- self._registration_order = list()
4562- super(BzrDirFormatRegistry, self).__init__()
4563-
4564- def aliases(self):
4565- """Return a set of the format names which are aliases."""
4566- return frozenset(self._aliases)
4567-
4568- def register_metadir(self, key,
4569- repository_format, help, native=True, deprecated=False,
4570- branch_format=None,
4571- tree_format=None,
4572- hidden=False,
4573- experimental=False,
4574- alias=False):
4575- """Register a metadir subformat.
4576-
4577- These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
4578- by the Repository/Branch/WorkingTreeformats.
4579-
4580- :param repository_format: The fully-qualified repository format class
4581- name as a string.
4582- :param branch_format: Fully-qualified branch format class name as
4583- a string.
4584- :param tree_format: Fully-qualified tree format class name as
4585- a string.
4586- """
4587- # This should be expanded to support setting WorkingTree and Branch
4588- # formats, once BzrDirMetaFormat1 supports that.
4589- def _load(full_name):
4590- mod_name, factory_name = full_name.rsplit('.', 1)
4591- try:
4592- mod = __import__(mod_name, globals(), locals(),
4593- [factory_name])
4594- except ImportError, e:
4595- raise ImportError('failed to load %s: %s' % (full_name, e))
4596- try:
4597- factory = getattr(mod, factory_name)
4598- except AttributeError:
4599- raise AttributeError('no factory %s in module %r'
4600- % (full_name, mod))
4601- return factory()
4602-
4603- def helper():
4604- bd = BzrDirMetaFormat1()
4605- if branch_format is not None:
4606- bd.set_branch_format(_load(branch_format))
4607- if tree_format is not None:
4608- bd.workingtree_format = _load(tree_format)
4609- if repository_format is not None:
4610- bd.repository_format = _load(repository_format)
4611- return bd
4612- self.register(key, helper, help, native, deprecated, hidden,
4613- experimental, alias)
4614-
4615- def register(self, key, factory, help, native=True, deprecated=False,
4616- hidden=False, experimental=False, alias=False):
4617- """Register a BzrDirFormat factory.
4618-
4619- The factory must be a callable that takes one parameter: the key.
4620- It must produce an instance of the BzrDirFormat when called.
4621-
4622- This function mainly exists to prevent the info object from being
4623- supplied directly.
4624- """
4625- registry.Registry.register(self, key, factory, help,
4626- BzrDirFormatInfo(native, deprecated, hidden, experimental))
4627- if alias:
4628- self._aliases.add(key)
4629- self._registration_order.append(key)
4630-
4631- def register_lazy(self, key, module_name, member_name, help, native=True,
4632- deprecated=False, hidden=False, experimental=False, alias=False):
4633- registry.Registry.register_lazy(self, key, module_name, member_name,
4634- help, BzrDirFormatInfo(native, deprecated, hidden, experimental))
4635- if alias:
4636- self._aliases.add(key)
4637- self._registration_order.append(key)
4638-
4639- def set_default(self, key):
4640- """Set the 'default' key to be a clone of the supplied key.
4641-
4642- This method must be called once and only once.
4643- """
4644- registry.Registry.register(self, 'default', self.get(key),
4645- self.get_help(key), info=self.get_info(key))
4646- self._aliases.add('default')
4647-
4648- def set_default_repository(self, key):
4649- """Set the FormatRegistry default and Repository default.
4650-
4651- This is a transitional method while Repository.set_default_format
4652- is deprecated.
4653- """
4654- if 'default' in self:
4655- self.remove('default')
4656- self.set_default(key)
4657- format = self.get('default')()
4658-
4659- def make_bzrdir(self, key):
4660- return self.get(key)()
4661-
4662- def help_topic(self, topic):
4663- output = ""
4664- default_realkey = None
4665- default_help = self.get_help('default')
4666- help_pairs = []
4667- for key in self._registration_order:
4668- if key == 'default':
4669- continue
4670- help = self.get_help(key)
4671- if help == default_help:
4672- default_realkey = key
4673- else:
4674- help_pairs.append((key, help))
4675-
4676- def wrapped(key, help, info):
4677- if info.native:
4678- help = '(native) ' + help
4679- return ':%s:\n%s\n\n' % (key,
4680- textwrap.fill(help, initial_indent=' ',
4681- subsequent_indent=' ',
4682- break_long_words=False))
4683- if default_realkey is not None:
4684- output += wrapped(default_realkey, '(default) %s' % default_help,
4685- self.get_info('default'))
4686- deprecated_pairs = []
4687- experimental_pairs = []
4688- for key, help in help_pairs:
4689- info = self.get_info(key)
4690- if info.hidden:
4691- continue
4692- elif info.deprecated:
4693- deprecated_pairs.append((key, help))
4694- elif info.experimental:
4695- experimental_pairs.append((key, help))
4696- else:
4697- output += wrapped(key, help, info)
4698- output += "\nSee :doc:`formats-help` for more about storage formats."
4699- other_output = ""
4700- if len(experimental_pairs) > 0:
4701- other_output += "Experimental formats are shown below.\n\n"
4702- for key, help in experimental_pairs:
4703- info = self.get_info(key)
4704- other_output += wrapped(key, help, info)
4705- else:
4706- other_output += \
4707- "No experimental formats are available.\n\n"
4708- if len(deprecated_pairs) > 0:
4709- other_output += "\nDeprecated formats are shown below.\n\n"
4710- for key, help in deprecated_pairs:
4711- info = self.get_info(key)
4712- other_output += wrapped(key, help, info)
4713- else:
4714- other_output += \
4715- "\nNo deprecated formats are available.\n\n"
4716- other_output += \
4717- "\nSee :doc:`formats-help` for more about storage formats."
4718-
4719- if topic == 'other-formats':
4720- return other_output
4721- else:
4722- return output
4723+controldir.ControlDirFormat.register_server_prober(RemoteBzrProber)
4724
4725
4726 class RepositoryAcquisitionPolicy(object):
4727@@ -3845,33 +3085,73 @@
4728 return self._repository, False
4729
4730
4731-# Please register new formats after old formats so that formats
4732-# appear in chronological order and format descriptions can build
4733-# on previous ones.
4734-format_registry = BzrDirFormatRegistry()
4735+def register_metadir(registry, key,
4736+ repository_format, help, native=True, deprecated=False,
4737+ branch_format=None,
4738+ tree_format=None,
4739+ hidden=False,
4740+ experimental=False,
4741+ alias=False):
4742+ """Register a metadir subformat.
4743+
4744+ These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
4745+ by the Repository/Branch/WorkingTreeformats.
4746+
4747+ :param repository_format: The fully-qualified repository format class
4748+ name as a string.
4749+ :param branch_format: Fully-qualified branch format class name as
4750+ a string.
4751+ :param tree_format: Fully-qualified tree format class name as
4752+ a string.
4753+ """
4754+ # This should be expanded to support setting WorkingTree and Branch
4755+ # formats, once BzrDirMetaFormat1 supports that.
4756+ def _load(full_name):
4757+ mod_name, factory_name = full_name.rsplit('.', 1)
4758+ try:
4759+ factory = pyutils.get_named_object(mod_name, factory_name)
4760+ except ImportError, e:
4761+ raise ImportError('failed to load %s: %s' % (full_name, e))
4762+ except AttributeError:
4763+ raise AttributeError('no factory %s in module %r'
4764+ % (full_name, sys.modules[mod_name]))
4765+ return factory()
4766+
4767+ def helper():
4768+ bd = BzrDirMetaFormat1()
4769+ if branch_format is not None:
4770+ bd.set_branch_format(_load(branch_format))
4771+ if tree_format is not None:
4772+ bd.workingtree_format = _load(tree_format)
4773+ if repository_format is not None:
4774+ bd.repository_format = _load(repository_format)
4775+ return bd
4776+ registry.register(key, helper, help, native, deprecated, hidden,
4777+ experimental, alias)
4778+
4779 # The pre-0.8 formats have their repository format network name registered in
4780 # repository.py. MetaDir formats have their repository format network name
4781 # inferred from their disk format string.
4782-format_registry.register('weave', BzrDirFormat6,
4783+controldir.format_registry.register('weave', BzrDirFormat6,
4784 'Pre-0.8 format. Slower than knit and does not'
4785 ' support checkouts or shared repositories.',
4786 hidden=True,
4787 deprecated=True)
4788-format_registry.register_metadir('metaweave',
4789+register_metadir(controldir.format_registry, 'metaweave',
4790 'bzrlib.repofmt.weaverepo.RepositoryFormat7',
4791 'Transitional format in 0.8. Slower than knit.',
4792 branch_format='bzrlib.branch.BzrBranchFormat5',
4793 tree_format='bzrlib.workingtree.WorkingTreeFormat3',
4794 hidden=True,
4795 deprecated=True)
4796-format_registry.register_metadir('knit',
4797+register_metadir(controldir.format_registry, 'knit',
4798 'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
4799 'Format using knits. Recommended for interoperation with bzr <= 0.14.',
4800 branch_format='bzrlib.branch.BzrBranchFormat5',
4801 tree_format='bzrlib.workingtree.WorkingTreeFormat3',
4802 hidden=True,
4803 deprecated=True)
4804-format_registry.register_metadir('dirstate',
4805+register_metadir(controldir.format_registry, 'dirstate',
4806 'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
4807 help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
4808 'above when accessed over the network.',
4809@@ -3881,7 +3161,7 @@
4810 tree_format='bzrlib.workingtree.WorkingTreeFormat4',
4811 hidden=True,
4812 deprecated=True)
4813-format_registry.register_metadir('dirstate-tags',
4814+register_metadir(controldir.format_registry, 'dirstate-tags',
4815 'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
4816 help='New in 0.15: Fast local operations and improved scaling for '
4817 'network operations. Additionally adds support for tags.'
4818@@ -3890,7 +3170,7 @@
4819 tree_format='bzrlib.workingtree.WorkingTreeFormat4',
4820 hidden=True,
4821 deprecated=True)
4822-format_registry.register_metadir('rich-root',
4823+register_metadir(controldir.format_registry, 'rich-root',
4824 'bzrlib.repofmt.knitrepo.RepositoryFormatKnit4',
4825 help='New in 1.0. Better handling of tree roots. Incompatible with'
4826 ' bzr < 1.0.',
4827@@ -3898,7 +3178,7 @@
4828 tree_format='bzrlib.workingtree.WorkingTreeFormat4',
4829 hidden=True,
4830 deprecated=True)
4831-format_registry.register_metadir('dirstate-with-subtree',
4832+register_metadir(controldir.format_registry, 'dirstate-with-subtree',
4833 'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
4834 help='New in 0.15: Fast local operations and improved scaling for '
4835 'network operations. Additionally adds support for versioning nested '
4836@@ -3908,7 +3188,7 @@
4837 experimental=True,
4838 hidden=True,
4839 )
4840-format_registry.register_metadir('pack-0.92',
4841+register_metadir(controldir.format_registry, 'pack-0.92',
4842 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack1',
4843 help='New in 0.92: Pack-based format with data compatible with '
4844 'dirstate-tags format repositories. Interoperates with '
4845@@ -3917,7 +3197,7 @@
4846 branch_format='bzrlib.branch.BzrBranchFormat6',
4847 tree_format='bzrlib.workingtree.WorkingTreeFormat4',
4848 )
4849-format_registry.register_metadir('pack-0.92-subtree',
4850+register_metadir(controldir.format_registry, 'pack-0.92-subtree',
4851 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack3',
4852 help='New in 0.92: Pack-based format with data compatible with '
4853 'dirstate-with-subtree format repositories. Interoperates with '
4854@@ -3928,7 +3208,7 @@
4855 hidden=True,
4856 experimental=True,
4857 )
4858-format_registry.register_metadir('rich-root-pack',
4859+register_metadir(controldir.format_registry, 'rich-root-pack',
4860 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack4',
4861 help='New in 1.0: A variant of pack-0.92 that supports rich-root data '
4862 '(needed for bzr-svn and bzr-git).',
4863@@ -3936,7 +3216,7 @@
4864 tree_format='bzrlib.workingtree.WorkingTreeFormat4',
4865 hidden=True,
4866 )
4867-format_registry.register_metadir('1.6',
4868+register_metadir(controldir.format_registry, '1.6',
4869 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack5',
4870 help='A format that allows a branch to indicate that there is another '
4871 '(stacked) repository that should be used to access data that is '
4872@@ -3945,7 +3225,7 @@
4873 tree_format='bzrlib.workingtree.WorkingTreeFormat4',
4874 hidden=True,
4875 )
4876-format_registry.register_metadir('1.6.1-rich-root',
4877+register_metadir(controldir.format_registry, '1.6.1-rich-root',
4878 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack5RichRoot',
4879 help='A variant of 1.6 that supports rich-root data '
4880 '(needed for bzr-svn and bzr-git).',
4881@@ -3953,7 +3233,7 @@
4882 tree_format='bzrlib.workingtree.WorkingTreeFormat4',
4883 hidden=True,
4884 )
4885-format_registry.register_metadir('1.9',
4886+register_metadir(controldir.format_registry, '1.9',
4887 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6',
4888 help='A repository format using B+tree indexes. These indexes '
4889 'are smaller in size, have smarter caching and provide faster '
4890@@ -3962,7 +3242,7 @@
4891 tree_format='bzrlib.workingtree.WorkingTreeFormat4',
4892 hidden=True,
4893 )
4894-format_registry.register_metadir('1.9-rich-root',
4895+register_metadir(controldir.format_registry, '1.9-rich-root',
4896 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6RichRoot',
4897 help='A variant of 1.9 that supports rich-root data '
4898 '(needed for bzr-svn and bzr-git).',
4899@@ -3970,13 +3250,13 @@
4900 tree_format='bzrlib.workingtree.WorkingTreeFormat4',
4901 hidden=True,
4902 )
4903-format_registry.register_metadir('1.14',
4904+register_metadir(controldir.format_registry, '1.14',
4905 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6',
4906 help='A working-tree format that supports content filtering.',
4907 branch_format='bzrlib.branch.BzrBranchFormat7',
4908 tree_format='bzrlib.workingtree.WorkingTreeFormat5',
4909 )
4910-format_registry.register_metadir('1.14-rich-root',
4911+register_metadir(controldir.format_registry, '1.14-rich-root',
4912 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6RichRoot',
4913 help='A variant of 1.14 that supports rich-root data '
4914 '(needed for bzr-svn and bzr-git).',
4915@@ -3984,22 +3264,8 @@
4916 tree_format='bzrlib.workingtree.WorkingTreeFormat5',
4917 )
4918 # The following un-numbered 'development' formats should always just be aliases.
4919-format_registry.register_metadir('development-rich-root',
4920- 'bzrlib.repofmt.groupcompress_repo.RepositoryFormatCHK1',
4921- help='Current development format. Supports rich roots. Can convert data '
4922- 'to and from rich-root-pack (and anything compatible with '
4923- 'rich-root-pack) format repositories. Repositories and branches in '
4924- 'this format can only be read by bzr.dev. Please read '
4925- 'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
4926- 'before use.',
4927- branch_format='bzrlib.branch.BzrBranchFormat7',
4928- tree_format='bzrlib.workingtree.WorkingTreeFormat6',
4929- experimental=True,
4930- alias=True,
4931- hidden=True,
4932- )
4933-format_registry.register_metadir('development-subtree',
4934- 'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2Subtree',
4935+register_metadir(controldir.format_registry, 'development-subtree',
4936+ 'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2aSubtree',
4937 help='Current development format, subtree variant. Can convert data to and '
4938 'from pack-0.92-subtree (and anything compatible with '
4939 'pack-0.92-subtree) format repositories. Repositories and branches in '
4940@@ -4014,33 +3280,25 @@
4941 # This current non-alias status is simply because we did not introduce a
4942 # chk based subtree format.
4943 )
4944+register_metadir(controldir.format_registry, 'development5-subtree',
4945+ 'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2Subtree',
4946+ help='Development format, subtree variant. Can convert data to and '
4947+ 'from pack-0.92-subtree (and anything compatible with '
4948+ 'pack-0.92-subtree) format repositories. Repositories and branches in '
4949+ 'this format can only be read by bzr.dev. Please read '
4950+ 'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
4951+ 'before use.',
4952+ branch_format='bzrlib.branch.BzrBranchFormat7',
4953+ tree_format='bzrlib.workingtree.WorkingTreeFormat6',
4954+ experimental=True,
4955+ hidden=True,
4956+ alias=False,
4957+ )
4958
4959 # And the development formats above will have aliased one of the following:
4960-format_registry.register_metadir('development6-rich-root',
4961- 'bzrlib.repofmt.groupcompress_repo.RepositoryFormatCHK1',
4962- help='pack-1.9 with 255-way hashed CHK inv, group compress, rich roots '
4963- 'Please read '
4964- 'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
4965- 'before use.',
4966- branch_format='bzrlib.branch.BzrBranchFormat7',
4967- tree_format='bzrlib.workingtree.WorkingTreeFormat6',
4968- hidden=True,
4969- experimental=True,
4970- )
4971-
4972-format_registry.register_metadir('development7-rich-root',
4973- 'bzrlib.repofmt.groupcompress_repo.RepositoryFormatCHK2',
4974- help='pack-1.9 with 255-way hashed CHK inv, bencode revision, group compress, '
4975- 'rich roots. Please read '
4976- 'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
4977- 'before use.',
4978- branch_format='bzrlib.branch.BzrBranchFormat7',
4979- tree_format='bzrlib.workingtree.WorkingTreeFormat6',
4980- hidden=True,
4981- experimental=True,
4982- )
4983-
4984-format_registry.register_metadir('2a',
4985+
4986+# Finally, the current format.
4987+register_metadir(controldir.format_registry, '2a',
4988 'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2a',
4989 help='First format for bzr 2.0 series.\n'
4990 'Uses group-compress storage.\n'
4991@@ -4049,12 +3307,12 @@
4992 # 'rich roots. Supported by bzr 1.16 and later.',
4993 branch_format='bzrlib.branch.BzrBranchFormat7',
4994 tree_format='bzrlib.workingtree.WorkingTreeFormat6',
4995- experimental=True,
4996+ experimental=False,
4997 )
4998
4999 # The following format should be an alias for the rich root equivalent
5000 # of the default format
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches