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
=== modified file '.bzrignore'
--- .bzrignore 2010-04-01 04:41:18 +0000
+++ .bzrignore 2011-02-09 08:08:20 +0000
@@ -19,7 +19,8 @@
19./doc/**/*.html19./doc/**/*.html
20./doc/developers/performance.png20./doc/developers/performance.png
21./doc/en/user-reference/*.txt21./doc/en/user-reference/*.txt
22./doc/en/release-notes/*.txt22./doc/en/release-notes/index.txt
23./doc/en/release-notes/NEWS.txt
23BRANCH-INFO24BRANCH-INFO
24# setup.py working directory25# setup.py working directory
25./build26./build
2627
=== modified file '.testr.conf'
--- .testr.conf 2010-02-28 10:08:29 +0000
+++ .testr.conf 2011-02-09 08:08:20 +0000
@@ -1,3 +1,4 @@
1[DEFAULT]1[DEFAULT]
2test_command=./bzr selftest --subunit $IDOPTION2test_command=./bzr selftest --subunit $IDOPTION $LISTOPT
3test_id_option=--load-list $IDFILE3test_id_option=--load-list $IDFILE
4test_list_option=--list
45
=== modified file 'Makefile'
--- Makefile 2010-04-06 06:59:03 +0000
+++ Makefile 2011-02-09 08:08:20 +0000
@@ -39,8 +39,14 @@
39check: docs check-nodocs39check: docs check-nodocs
4040
41check-nodocs: extensions41check-nodocs: extensions
42 set -e
42 # Generate a stream for PQM to watch.43 # Generate a stream for PQM to watch.
44 -$(RM) -f selftest.log
43 $(PYTHON) -Werror -O ./bzr selftest --subunit $(tests) | tee selftest.log45 $(PYTHON) -Werror -O ./bzr selftest --subunit $(tests) | tee selftest.log
46 # An empty log file should catch errors in the $(PYTHON)
47 # command above (the '|' swallow any errors since 'make'
48 # sees the 'tee' exit code for the whole line
49 if [ ! -s selftest.log ] ; then exit 1 ; fi
44 # Check that there were no errors reported.50 # Check that there were no errors reported.
45 subunit-stats < selftest.log51 subunit-stats < selftest.log
4652
@@ -133,11 +139,13 @@
133 doc/developers/Makefile \139 doc/developers/Makefile \
134 doc/developers/make.bat140 doc/developers/make.bat
135141
142NEWS_FILES = $(wildcard doc/en/release-notes/bzr-*.txt)
143
136doc/en/user-reference/index.txt: $(MAN_DEPENDENCIES)144doc/en/user-reference/index.txt: $(MAN_DEPENDENCIES)
137 $(PYTHON) tools/generate_docs.py -o $@ rstx145 $(PYTHON) tools/generate_docs.py -o $@ rstx
138146
139doc/en/release-notes/index.txt: NEWS tools/generate_release_notes.py147doc/en/release-notes/index.txt: $(NEWS_FILES) tools/generate_release_notes.py
140 $(PYTHON) tools/generate_release_notes.py NEWS $@148 $(PYTHON) tools/generate_release_notes.py $@ $(NEWS_FILES)
141149
142doc/%/Makefile: doc/en/Makefile150doc/%/Makefile: doc/en/Makefile
143 $(PYTHON) -c "import shutil; shutil.copyfile('$<', '$@')"151 $(PYTHON) -c "import shutil; shutil.copyfile('$<', '$@')"
@@ -296,10 +304,10 @@
296 $(rst2html) --stylesheet=default.css $< $@304 $(rst2html) --stylesheet=default.css $< $@
297305
298%.html: %.txt306%.html: %.txt
299 $(rst2html) --stylesheet=../../default.css $< $@307 $(rst2html) --stylesheet=../../default.css $< "$@"
300308
301doc/en/release-notes/NEWS.txt: NEWS309doc/en/release-notes/NEWS.txt: $(NEWS_FILES) tools/generate_release_notes.py
302 $(PYTHON) -c "import shutil; shutil.copyfile('$<', '$@')"310 $(PYTHON) tools/generate_release_notes.py "$@" $(NEWS_FILES)
303311
304upgrade_guide_dependencies = $(wildcard $(addsuffix /*.txt, doc/en/upgrade-guide)) 312upgrade_guide_dependencies = $(wildcard $(addsuffix /*.txt, doc/en/upgrade-guide))
305313
306314
=== added file 'NEWS'
--- NEWS 1970-01-01 00:00:00 +0000
+++ NEWS 2011-02-09 08:08:20 +0000
@@ -0,0 +1,2 @@
1The NEWS file has been moved and split into multiple files (one per release
2series). The NEWS files are now found in doc/en/release-notes/.
03
=== modified file 'README'
--- README 2010-01-29 14:09:05 +0000
+++ README 2011-02-09 08:08:20 +0000
@@ -36,7 +36,7 @@
36It also directly supports and encourages a large number of development best36It also directly supports and encourages a large number of development best
37practices like refactoring and pre-commit regression testing. Users can37practices like refactoring and pre-commit regression testing. Users can
38choose between our command line tool and our cross-platform GUI application.38choose between our command line tool and our cross-platform GUI application.
39For further details, see our website at http://bazaar-vcs.org/en.39For further details, see our website at http://bazaar.canonical.com/en/
4040
41Feedback41Feedback
42========42========
4343
=== modified file 'bzr'
--- bzr 2011-02-04 14:04:18 +0000
+++ bzr 2011-02-09 08:08:20 +0000
@@ -23,7 +23,7 @@
23import warnings23import warnings
2424
25# update this on each release25# update this on each release
26_script_version = (2, 2, 5)26_script_version = (2, 4, 0)
2727
28try:28try:
29 version_info = sys.version_info29 version_info = sys.version_info
3030
=== modified file 'bzrlib/__init__.py'
--- bzrlib/__init__.py 2011-02-04 14:04:18 +0000
+++ bzrlib/__init__.py 2011-02-09 08:08:20 +0000
@@ -1,4 +1,4 @@
1# Copyright (C) 2005-2010 Canonical Ltd1# Copyright (C) 2005-2011 Canonical Ltd
2#2#
3# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -52,10 +52,10 @@
52# Python version 2.0 is (2, 0, 0, 'final', 0)." Additionally we use a52# Python version 2.0 is (2, 0, 0, 'final', 0)." Additionally we use a
53# releaselevel of 'dev' for unreleased under-development code.53# releaselevel of 'dev' for unreleased under-development code.
5454
55version_info = (2, 2, 5, 'dev', 0)55version_info = (2, 4, 0, 'dev', 1)
5656
57# API compatibility version57# API compatibility version
58api_minimum_version = (2, 2, 0)58api_minimum_version = (2, 4, 0)
5959
6060
61def _format_version_tuple(version_info):61def _format_version_tuple(version_info):
@@ -71,17 +71,17 @@
71 1.0.071 1.0.0
72 >>> print _format_version_tuple((1, 2, 0, 'dev', 0))72 >>> print _format_version_tuple((1, 2, 0, 'dev', 0))
73 1.2.0dev73 1.2.0dev
74 >>> print bzrlib._format_version_tuple((1, 2, 0, 'dev', 1))74 >>> print _format_version_tuple((1, 2, 0, 'dev', 1))
75 1.2.0dev175 1.2.0dev1
76 >>> print _format_version_tuple((1, 1, 1, 'candidate', 2))76 >>> print _format_version_tuple((1, 1, 1, 'candidate', 2))
77 1.1.1rc277 1.1.1rc2
78 >>> print bzrlib._format_version_tuple((2, 1, 0, 'beta', 1))78 >>> print _format_version_tuple((2, 1, 0, 'beta', 1))
79 2.1b179 2.1b1
80 >>> print _format_version_tuple((1, 4, 0))80 >>> print _format_version_tuple((1, 4, 0))
81 1.4.081 1.4.0
82 >>> print _format_version_tuple((1, 4))82 >>> print _format_version_tuple((1, 4))
83 1.483 1.4
84 >>> print bzrlib._format_version_tuple((2, 1, 0, 'final', 1))84 >>> print _format_version_tuple((2, 1, 0, 'final', 1))
85 Traceback (most recent call last):85 Traceback (most recent call last):
86 ...86 ...
87 ValueError: version_info (2, 1, 0, 'final', 1) not valid87 ValueError: version_info (2, 1, 0, 'final', 1) not valid
8888
=== modified file 'bzrlib/_btree_serializer_pyx.pyx'
--- bzrlib/_btree_serializer_pyx.pyx 2010-02-17 17:11:16 +0000
+++ bzrlib/_btree_serializer_pyx.pyx 2011-02-09 08:08:20 +0000
@@ -33,6 +33,7 @@
33 char *PyString_AsString(object p) except NULL33 char *PyString_AsString(object p) except NULL
34 object PyString_FromStringAndSize(char *, Py_ssize_t)34 object PyString_FromStringAndSize(char *, Py_ssize_t)
35 PyObject *PyString_FromStringAndSize_ptr "PyString_FromStringAndSize" (char *, Py_ssize_t)35 PyObject *PyString_FromStringAndSize_ptr "PyString_FromStringAndSize" (char *, Py_ssize_t)
36 object PyString_FromFormat(char *, ...)
36 int PyString_CheckExact(object s)37 int PyString_CheckExact(object s)
37 int PyString_CheckExact_ptr "PyString_CheckExact" (PyObject *)38 int PyString_CheckExact_ptr "PyString_CheckExact" (PyObject *)
38 Py_ssize_t PyString_Size(object p)39 Py_ssize_t PyString_Size(object p)
@@ -49,19 +50,31 @@
49 PyObject *PyTuple_GET_ITEM_ptr_object "PyTuple_GET_ITEM" (object tpl, int index)50 PyObject *PyTuple_GET_ITEM_ptr_object "PyTuple_GET_ITEM" (object tpl, int index)
50 void Py_INCREF(object)51 void Py_INCREF(object)
51 void Py_DECREF_ptr "Py_DECREF" (PyObject *)52 void Py_DECREF_ptr "Py_DECREF" (PyObject *)
53 void *PyMem_Malloc(size_t nbytes)
54 void PyMem_Free(void *)
55 void memset(void *, int, size_t)
5256
53cdef extern from "string.h":57cdef extern from "string.h":
54 void *memcpy(void *dest, void *src, size_t n)58 void *memcpy(void *dest, void *src, size_t n)
55 void *memchr(void *s, int c, size_t n)59 void *memchr(void *s, int c, size_t n)
60 int memcmp(void *s1, void *s2, size_t n)
56 # GNU extension61 # GNU extension
57 # void *memrchr(void *s, int c, size_t n)62 # void *memrchr(void *s, int c, size_t n)
58 int strncmp(char *s1, char *s2, size_t n)63 int strncmp(char *s1, char *s2, size_t n)
64 unsigned long strtoul(char *s1, char **out, int base)
65 long long strtoll(char *s1, char **out, int base)
66
5967
60# It seems we need to import the definitions so that the pyrex compiler has68# It seems we need to import the definitions so that the pyrex compiler has
61# local names to access them.69# local names to access them.
62from _static_tuple_c cimport StaticTuple, \70from _static_tuple_c cimport StaticTuple, \
63 import_static_tuple_c, StaticTuple_New, \71 import_static_tuple_c, StaticTuple_New, \
64 StaticTuple_Intern, StaticTuple_SET_ITEM, StaticTuple_CheckExact72 StaticTuple_Intern, StaticTuple_SET_ITEM, StaticTuple_CheckExact, \
73 StaticTuple_GET_SIZE, StaticTuple_GET_ITEM
74# This tells the test infrastructure that StaticTuple is a class, so we don't
75# have to worry about exception checking.
76## extern cdef class StaticTuple
77import sys
6578
6679
67# TODO: Find some way to import this from _dirstate_helpers80# TODO: Find some way to import this from _dirstate_helpers
@@ -103,7 +116,6 @@
103 Py_DECREF_ptr(py_str)116 Py_DECREF_ptr(py_str)
104 return result117 return result
105118
106from bzrlib import _static_tuple_c
107# This sets up the StaticTuple C_API functionality119# This sets up the StaticTuple C_API functionality
108import_static_tuple_c()120import_static_tuple_c()
109121
@@ -315,6 +327,537 @@
315 return parser.parse()327 return parser.parse()
316328
317329
330# TODO: We can go from 8 byte offset + 4 byte length to a simple lookup,
331# because the block_offset + length is likely to be repeated. However,
332# the big win there is to cache across pages, and not just one page
333# Though if we did cache in a page, we could certainly use a short int.
334# And this goes from 40 bytes to 30 bytes.
335# One slightly ugly option would be to cache block offsets in a global.
336# However, that leads to thread-safety issues, etc.
337ctypedef struct gc_chk_sha1_record:
338 long long block_offset
339 unsigned int block_length
340 unsigned int record_start
341 unsigned int record_end
342 char sha1[20]
343
344
345cdef int _unhexbuf[256]
346cdef char *_hexbuf
347_hexbuf = '0123456789abcdef'
348
349cdef _populate_unhexbuf():
350 cdef int i
351 for i from 0 <= i < 256:
352 _unhexbuf[i] = -1
353 for i from 0 <= i < 10: # 0123456789 => map to the raw number
354 _unhexbuf[(i + c'0')] = i
355 for i from 10 <= i < 16: # abcdef => 10, 11, 12, 13, 14, 15, 16
356 _unhexbuf[(i - 10 + c'a')] = i
357 for i from 10 <= i < 16: # ABCDEF => 10, 11, 12, 13, 14, 15, 16
358 _unhexbuf[(i - 10 + c'A')] = i
359_populate_unhexbuf()
360
361
362cdef int _unhexlify_sha1(char *as_hex, char *as_bin): # cannot_raise
363 """Take the hex sha1 in as_hex and make it binary in as_bin
364
365 Same as binascii.unhexlify, but working on C strings, not Python objects.
366 """
367 cdef int top
368 cdef int bot
369 cdef int i, j
370 cdef char *cur
371
372 # binascii does this using isupper() and tolower() and ?: syntax. I'm
373 # guessing a simple lookup array should be faster.
374 j = 0
375 for i from 0 <= i < 20:
376 top = _unhexbuf[<unsigned char>(as_hex[j])]
377 j = j + 1
378 bot = _unhexbuf[<unsigned char>(as_hex[j])]
379 j = j + 1
380 if top == -1 or bot == -1:
381 return 0
382 as_bin[i] = <unsigned char>((top << 4) + bot);
383 return 1
384
385
386def _py_unhexlify(as_hex):
387 """For the test infrastructure, just thunks to _unhexlify_sha1"""
388 if len(as_hex) != 40 or not PyString_CheckExact(as_hex):
389 raise ValueError('not a 40-byte hex digest')
390 as_bin = PyString_FromStringAndSize(NULL, 20)
391 if _unhexlify_sha1(PyString_AS_STRING(as_hex), PyString_AS_STRING(as_bin)):
392 return as_bin
393 return None
394
395
396cdef void _hexlify_sha1(char *as_bin, char *as_hex): # cannot_raise
397 cdef int i, j
398 cdef char c
399
400 j = 0
401 for i from 0 <= i < 20:
402 c = as_bin[i]
403 as_hex[j] = _hexbuf[(c>>4)&0xf]
404 j = j + 1
405 as_hex[j] = _hexbuf[(c)&0xf]
406 j = j + 1
407
408
409def _py_hexlify(as_bin):
410 """For test infrastructure, thunk to _hexlify_sha1"""
411 if len(as_bin) != 20 or not PyString_CheckExact(as_bin):
412 raise ValueError('not a 20-byte binary digest')
413 as_hex = PyString_FromStringAndSize(NULL, 40)
414 _hexlify_sha1(PyString_AS_STRING(as_bin), PyString_AS_STRING(as_hex))
415 return as_hex
416
417
418cdef int _key_to_sha1(key, char *sha1): # cannot_raise
419 """Map a key into its sha1 content.
420
421 :param key: A tuple of style ('sha1:abcd...',)
422 :param sha1: A char buffer of 20 bytes
423 :return: 1 if this could be converted, 0 otherwise
424 """
425 cdef char *c_val
426 cdef PyObject *p_val
427
428 if StaticTuple_CheckExact(key) and StaticTuple_GET_SIZE(key) == 1:
429 p_val = <PyObject *>StaticTuple_GET_ITEM(key, 0)
430 elif (PyTuple_CheckExact(key) and PyTuple_GET_SIZE(key) == 1):
431 p_val = PyTuple_GET_ITEM_ptr_object(key, 0)
432 else:
433 # Not a tuple or a StaticTuple
434 return 0
435 if (PyString_CheckExact_ptr(p_val) and PyString_GET_SIZE_ptr(p_val) == 45):
436 c_val = PyString_AS_STRING_ptr(p_val)
437 else:
438 return 0
439 if strncmp(c_val, 'sha1:', 5) != 0:
440 return 0
441 if not _unhexlify_sha1(c_val + 5, sha1):
442 return 0
443 return 1
444
445
446def _py_key_to_sha1(key):
447 """Map a key to a simple sha1 string.
448
449 This is a testing thunk to the C function.
450 """
451 as_bin_sha = PyString_FromStringAndSize(NULL, 20)
452 if _key_to_sha1(key, PyString_AS_STRING(as_bin_sha)):
453 return as_bin_sha
454 return None
455
456
457cdef StaticTuple _sha1_to_key(char *sha1):
458 """Compute a ('sha1:abcd',) key for a given sha1."""
459 cdef StaticTuple key
460 cdef object hexxed
461 cdef char *c_buf
462 hexxed = PyString_FromStringAndSize(NULL, 45)
463 c_buf = PyString_AS_STRING(hexxed)
464 memcpy(c_buf, 'sha1:', 5)
465 _hexlify_sha1(sha1, c_buf+5)
466 key = StaticTuple_New(1)
467 Py_INCREF(hexxed)
468 StaticTuple_SET_ITEM(key, 0, hexxed)
469 # This is a bit expensive. To parse 120 keys takes 48us, to return them all
470 # can be done in 66.6us (so 18.6us to build them all).
471 # Adding simple hash() here brings it to 76.6us (so computing the hash
472 # value of 120keys is 10us), Intern is 86.9us (another 10us to look and add
473 # them to the intern structure.)
474 # However, since we only intern keys that are in active use, it is probably
475 # a win. Since they would have been read from elsewhere anyway.
476 # We *could* hang the PyObject form off of the gc_chk_sha1_record for ones
477 # that we have deserialized. Something to think about, at least.
478 key = StaticTuple_Intern(key)
479 return key
480
481
482def _py_sha1_to_key(sha1_bin):
483 """Test thunk to check the sha1 mapping."""
484 if not PyString_CheckExact(sha1_bin) or PyString_GET_SIZE(sha1_bin) != 20:
485 raise ValueError('sha1_bin must be a str of exactly 20 bytes')
486 return _sha1_to_key(PyString_AS_STRING(sha1_bin))
487
488
489cdef unsigned int _sha1_to_uint(char *sha1): # cannot_raise
490 cdef unsigned int val
491 # Must be in MSB, because that is how the content is sorted
492 val = (((<unsigned int>(sha1[0]) & 0xff) << 24)
493 | ((<unsigned int>(sha1[1]) & 0xff) << 16)
494 | ((<unsigned int>(sha1[2]) & 0xff) << 8)
495 | ((<unsigned int>(sha1[3]) & 0xff) << 0))
496 return val
497
498
499cdef _format_record_py24(gc_chk_sha1_record *record):
500 """Python2.4 PyString_FromFormat doesn't have %u.
501
502 It only has %d and %ld. We would really like to even have %llu, which
503 is only in python2.7. So we go back into casting to regular objects.
504 """
505 return "%s %s %s %s" % (record.block_offset, record.block_length,
506 record.record_start, record.record_end)
507
508
509cdef _format_record(gc_chk_sha1_record *record):
510 # This is inefficient to go from a logical state back to a
511 # string, but it makes things work a bit better internally for now.
512 if record.block_offset >= 0xFFFFFFFF:
513 # %llu is what we really want, but unfortunately it was only added
514 # in python 2.7... :(
515 block_offset_str = str(record.block_offset)
516 value = PyString_FromFormat('%s %lu %lu %lu',
517 PyString_AS_STRING(block_offset_str),
518 record.block_length,
519 record.record_start, record.record_end)
520 else:
521 value = PyString_FromFormat('%lu %lu %lu %lu',
522 <unsigned long>record.block_offset,
523 record.block_length,
524 record.record_start, record.record_end)
525 return value
526
527ctypedef object (*formatproc)(gc_chk_sha1_record *)
528cdef formatproc _record_formatter
529_record_formatter = _format_record
530if sys.version_info[:2] == (2, 4):
531 _record_formatter = _format_record_py24
532
533
534cdef class GCCHKSHA1LeafNode:
535 """Track all the entries for a given leaf node."""
536
537 cdef gc_chk_sha1_record *records
538 cdef public object last_key
539 cdef gc_chk_sha1_record *last_record
540 cdef public int num_records
541 # This is the number of bits to shift to get to the interesting byte. A
542 # value of 24 means that the very first byte changes across all keys.
543 # Anything else means that there is a common prefix of bits that we can
544 # ignore. 0 means that at least the first 3 bytes are identical, though
545 # that is going to be very rare
546 cdef public unsigned char common_shift
547 # This maps an interesting byte to the first record that matches.
548 # Equivalent to bisect.bisect_left(self.records, sha1), though only taking
549 # into account that one byte.
550 cdef unsigned char offsets[257]
551
552 def __sizeof__(self):
553 # :( Why doesn't Pyrex let me do a simple sizeof(GCCHKSHA1LeafNode)
554 # like Cython? Explicitly enumerating everything here seems to leave my
555 # size off by 2 (286 bytes vs 288 bytes actual). I'm guessing it is an
556 # alignment/padding issue. Oh well- at least we scale properly with
557 # num_records and are very close to correct, which is what I care
558 # about.
559 # If we ever decide to require cython:
560 # return (sizeof(GCCHKSHA1LeafNode)
561 # + sizeof(gc_chk_sha1_record)*self.num_records)
562 return (sizeof(PyObject) + sizeof(void*) + sizeof(int)
563 + sizeof(gc_chk_sha1_record*) + sizeof(PyObject *)
564 + sizeof(gc_chk_sha1_record*) + sizeof(char)
565 + sizeof(unsigned char)*257
566 + sizeof(gc_chk_sha1_record)*self.num_records)
567
568 def __dealloc__(self):
569 if self.records != NULL:
570 PyMem_Free(self.records)
571 self.records = NULL
572
573 def __init__(self, bytes):
574 self._parse_bytes(bytes)
575 self.last_key = None
576 self.last_record = NULL
577
578 property min_key:
579 def __get__(self):
580 if self.num_records > 0:
581 return _sha1_to_key(self.records[0].sha1)
582 return None
583
584 property max_key:
585 def __get__(self):
586 if self.num_records > 0:
587 return _sha1_to_key(self.records[self.num_records-1].sha1)
588 return None
589
590 cdef StaticTuple _record_to_value_and_refs(self,
591 gc_chk_sha1_record *record):
592 """Extract the refs and value part of this record."""
593 cdef StaticTuple value_and_refs
594 cdef StaticTuple empty
595 value_and_refs = StaticTuple_New(2)
596 value = _record_formatter(record)
597 Py_INCREF(value)
598 StaticTuple_SET_ITEM(value_and_refs, 0, value)
599 # Always empty refs
600 empty = StaticTuple_New(0)
601 Py_INCREF(empty)
602 StaticTuple_SET_ITEM(value_and_refs, 1, empty)
603 return value_and_refs
604
605 cdef StaticTuple _record_to_item(self, gc_chk_sha1_record *record):
606 """Turn a given record back into a fully fledged item.
607 """
608 cdef StaticTuple item
609 cdef StaticTuple key
610 cdef StaticTuple value_and_refs
611 cdef object value
612 key = _sha1_to_key(record.sha1)
613 item = StaticTuple_New(2)
614 Py_INCREF(key)
615 StaticTuple_SET_ITEM(item, 0, key)
616 value_and_refs = self._record_to_value_and_refs(record)
617 Py_INCREF(value_and_refs)
618 StaticTuple_SET_ITEM(item, 1, value_and_refs)
619 return item
620
621 cdef gc_chk_sha1_record* _lookup_record(self, char *sha1) except? NULL:
622 """Find a gc_chk_sha1_record that matches the sha1 supplied."""
623 cdef int lo, hi, mid, the_cmp
624 cdef int offset
625
626 # TODO: We can speed up misses by comparing this sha1 to the common
627 # bits, and seeing if the common prefix matches, if not, we don't
628 # need to search for anything because it cannot match
629 # Use the offset array to find the closest fit for this entry
630 # follow that up with bisecting, since multiple keys can be in one
631 # spot
632 # Bisecting dropped us from 7000 comparisons to 582 (4.8/key), using
633 # the offset array dropped us from 23us to 20us and 156 comparisions
634 # (1.3/key)
635 offset = self._offset_for_sha1(sha1)
636 lo = self.offsets[offset]
637 hi = self.offsets[offset+1]
638 if hi == 255:
639 # if hi == 255 that means we potentially ran off the end of the
640 # list, so push it up to num_records
641 # note that if 'lo' == 255, that is ok, because we can start
642 # searching from that part of the list.
643 hi = self.num_records
644 local_n_cmp = 0
645 while lo < hi:
646 mid = (lo + hi) / 2
647 the_cmp = memcmp(self.records[mid].sha1, sha1, 20)
648 if the_cmp == 0:
649 return &self.records[mid]
650 elif the_cmp < 0:
651 lo = mid + 1
652 else:
653 hi = mid
654 return NULL
655
656 def __contains__(self, key):
657 cdef char sha1[20]
658 cdef gc_chk_sha1_record *record
659 if _key_to_sha1(key, sha1):
660 # If it isn't a sha1 key, then it won't be in this leaf node
661 record = self._lookup_record(sha1)
662 if record != NULL:
663 self.last_key = key
664 self.last_record = record
665 return True
666 return False
667
668 def __getitem__(self, key):
669 cdef char sha1[20]
670 cdef gc_chk_sha1_record *record
671 record = NULL
672 if self.last_record != NULL and key is self.last_key:
673 record = self.last_record
674 elif _key_to_sha1(key, sha1):
675 record = self._lookup_record(sha1)
676 if record == NULL:
677 raise KeyError('key %r is not present' % (key,))
678 return self._record_to_value_and_refs(record)
679
680 def __len__(self):
681 return self.num_records
682
683 def all_keys(self):
684 cdef int i
685 result = []
686 for i from 0 <= i < self.num_records:
687 PyList_Append(result, _sha1_to_key(self.records[i].sha1))
688 return result
689
690 def all_items(self):
691 cdef int i
692 result = []
693 for i from 0 <= i < self.num_records:
694 item = self._record_to_item(&self.records[i])
695 PyList_Append(result, item)
696 return result
697
698 cdef int _count_records(self, char *c_content, char *c_end): # cannot_raise
699 """Count how many records are in this section."""
700 cdef char *c_cur
701 cdef int num_records
702
703 c_cur = c_content
704 num_records = 0
705 while c_cur != NULL and c_cur < c_end:
706 c_cur = <char *>memchr(c_cur, c'\n', c_end - c_cur);
707 if c_cur == NULL:
708 break
709 c_cur = c_cur + 1
710 num_records = num_records + 1
711 return num_records
712
713 cdef _parse_bytes(self, bytes):
714 """Parse the string 'bytes' into content."""
715 cdef char *c_bytes
716 cdef char *c_cur
717 cdef char *c_end
718 cdef Py_ssize_t n_bytes
719 cdef int num_records
720 cdef int entry
721 cdef gc_chk_sha1_record *cur_record
722
723 if not PyString_CheckExact(bytes):
724 raise TypeError('We only support parsing plain 8-bit strings.')
725 # Pass 1, count how many records there will be
726 n_bytes = PyString_GET_SIZE(bytes)
727 c_bytes = PyString_AS_STRING(bytes)
728 c_end = c_bytes + n_bytes
729 if strncmp(c_bytes, 'type=leaf\n', 10):
730 raise ValueError("bytes did not start with 'type=leaf\\n': %r"
731 % (bytes[:10],))
732 c_cur = c_bytes + 10
733 num_records = self._count_records(c_cur, c_end)
734 # Now allocate the memory for these items, and go to town
735 self.records = <gc_chk_sha1_record*>PyMem_Malloc(num_records *
736 (sizeof(unsigned short) + sizeof(gc_chk_sha1_record)))
737 self.num_records = num_records
738 cur_record = self.records
739 entry = 0
740 while c_cur != NULL and c_cur < c_end and entry < num_records:
741 c_cur = self._parse_one_entry(c_cur, c_end, cur_record)
742 cur_record = cur_record + 1
743 entry = entry + 1
744 if (entry != self.num_records
745 or c_cur != c_end
746 or cur_record != self.records + self.num_records):
747 raise ValueError('Something went wrong while parsing.')
748 # Pass 3: build the offset map
749 self._compute_common()
750
751 cdef char *_parse_one_entry(self, char *c_cur, char *c_end,
752 gc_chk_sha1_record *cur_record) except NULL:
753 """Read a single sha record from the bytes.
754 :param c_cur: The pointer to the start of bytes
755 :param cur_record:
756 """
757 cdef char *c_next
758 if strncmp(c_cur, 'sha1:', 5):
759 raise ValueError('line did not start with sha1: %r'
760 % (safe_string_from_size(c_cur, 10),))
761 c_cur = c_cur + 5
762 c_next = <char *>memchr(c_cur, c'\0', c_end - c_cur)
763 if c_next == NULL or (c_next - c_cur != 40):
764 raise ValueError('Line did not contain 40 hex bytes')
765 if not _unhexlify_sha1(c_cur, cur_record.sha1):
766 raise ValueError('We failed to unhexlify')
767 c_cur = c_next + 1
768 if c_cur[0] != c'\0':
769 raise ValueError('only 1 null, not 2 as expected')
770 c_cur = c_cur + 1
771 cur_record.block_offset = strtoll(c_cur, &c_next, 10)
772 if c_cur == c_next or c_next[0] != c' ':
773 raise ValueError('Failed to parse block offset')
774 c_cur = c_next + 1
775 cur_record.block_length = strtoul(c_cur, &c_next, 10)
776 if c_cur == c_next or c_next[0] != c' ':
777 raise ValueError('Failed to parse block length')
778 c_cur = c_next + 1
779 cur_record.record_start = strtoul(c_cur, &c_next, 10)
780 if c_cur == c_next or c_next[0] != c' ':
781 raise ValueError('Failed to parse block length')
782 c_cur = c_next + 1
783 cur_record.record_end = strtoul(c_cur, &c_next, 10)
784 if c_cur == c_next or c_next[0] != c'\n':
785 raise ValueError('Failed to parse record end')
786 c_cur = c_next + 1
787 return c_cur
788
789 cdef int _offset_for_sha1(self, char *sha1) except -1:
790 """Find the first interesting 8-bits of this sha1."""
791 cdef int this_offset
792 cdef unsigned int as_uint
793 as_uint = _sha1_to_uint(sha1)
794 this_offset = (as_uint >> self.common_shift) & 0xFF
795 return this_offset
796
797 def _get_offset_for_sha1(self, sha1):
798 return self._offset_for_sha1(PyString_AS_STRING(sha1))
799
800 cdef _compute_common(self):
801 cdef unsigned int first
802 cdef unsigned int this
803 cdef unsigned int common_mask
804 cdef unsigned char common_shift
805 cdef int i
806 cdef int offset, this_offset
807 cdef int max_offset
808 # The idea with the offset map is that we should be able to quickly
809 # jump to the key that matches a gives sha1. We know that the keys are
810 # in sorted order, and we know that a lot of the prefix is going to be
811 # the same across them.
812 # By XORing the records together, we can determine what bits are set in
813 # all of them
814 if self.num_records < 2:
815 # Everything is in common if you have 0 or 1 leaves
816 # So we'll always just shift to the first byte
817 self.common_shift = 24
818 else:
819 common_mask = 0xFFFFFFFF
820 first = _sha1_to_uint(self.records[0].sha1)
821 for i from 0 < i < self.num_records:
822 this = _sha1_to_uint(self.records[i].sha1)
823 common_mask = (~(first ^ this)) & common_mask
824 common_shift = 24
825 while common_mask & 0x80000000 and common_shift > 0:
826 common_mask = common_mask << 1
827 common_shift = common_shift - 1
828 self.common_shift = common_shift
829 offset = 0
830 max_offset = self.num_records
831 # We cap this loop at 254 records. All the other offsets just get
832 # filled with 0xff as the singleton saying 'too many'.
833 # It means that if we have >255 records we have to bisect the second
834 # half of the list, but this is going to be very rare in practice.
835 if max_offset > 255:
836 max_offset = 255
837 for i from 0 <= i < max_offset:
838 this_offset = self._offset_for_sha1(self.records[i].sha1)
839 while offset <= this_offset:
840 self.offsets[offset] = i
841 offset = offset + 1
842 while offset < 257:
843 self.offsets[offset] = max_offset
844 offset = offset + 1
845
846 def _get_offsets(self):
847 cdef int i
848 result = []
849 for i from 0 <= i < 257:
850 PyList_Append(result, self.offsets[i])
851 return result
852
853
854def _parse_into_chk(bytes, key_length, ref_list_length):
855 """Parse into a format optimized for chk records."""
856 assert key_length == 1
857 assert ref_list_length == 0
858 return GCCHKSHA1LeafNode(bytes)
859
860
318def _flatten_node(node, reference_lists):861def _flatten_node(node, reference_lists):
319 """Convert a node into the serialized form.862 """Convert a node into the serialized form.
320863
321864
=== modified file 'bzrlib/_chk_map_pyx.pyx'
--- bzrlib/_chk_map_pyx.pyx 2010-05-16 15:18:43 +0000
+++ bzrlib/_chk_map_pyx.pyx 2011-02-09 08:08:20 +0000
@@ -413,7 +413,7 @@
413 cdef Py_ssize_t byte_size, pos, file_id_len413 cdef Py_ssize_t byte_size, pos, file_id_len
414414
415 if not PyString_CheckExact(bytes):415 if not PyString_CheckExact(bytes):
416 raise TypeError('bytes must be a string')416 raise TypeError('bytes must be a string, got %r' % (type(bytes),))
417 byte_str = PyString_AS_STRING(bytes)417 byte_str = PyString_AS_STRING(bytes)
418 byte_size = PyString_GET_SIZE(bytes)418 byte_size = PyString_GET_SIZE(bytes)
419 byte_end = byte_str + byte_size419 byte_end = byte_str + byte_size
@@ -421,7 +421,8 @@
421 if cur_end == NULL:421 if cur_end == NULL:
422 raise ValueError('No kind section found.')422 raise ValueError('No kind section found.')
423 if cur_end[1] != c' ':423 if cur_end[1] != c' ':
424 raise ValueError('Kind section should end with ": "')424 raise ValueError(
425 'Kind section should end with ": ", got %r' % str(cur_end[:2],))
425 file_id_str = cur_end + 2426 file_id_str = cur_end + 2
426 # file_id is now the data up until the next newline427 # file_id is now the data up until the next newline
427 cur_end = <char*>memchr(file_id_str, c'\n', byte_end - file_id_str)428 cur_end = <char*>memchr(file_id_str, c'\n', byte_end - file_id_str)
428429
=== modified file 'bzrlib/_dirstate_helpers_pyx.pyx'
--- bzrlib/_dirstate_helpers_pyx.pyx 2010-05-20 02:57:52 +0000
+++ bzrlib/_dirstate_helpers_pyx.pyx 2011-02-09 08:08:20 +0000
@@ -1,4 +1,4 @@
1# Copyright (C) 2007, 2008, 2010 Canonical Ltd1# Copyright (C) 2007-2010 Canonical Ltd
2#2#
3# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -118,6 +118,11 @@
118 # ??? memrchr is a GNU extension :(118 # ??? memrchr is a GNU extension :(
119 # void *memrchr(void *s, int c, size_t len)119 # void *memrchr(void *s, int c, size_t len)
120120
121# cimport all of the definitions we will need to access
122from _static_tuple_c cimport import_static_tuple_c, StaticTuple, \
123 StaticTuple_New, StaticTuple_SET_ITEM
124
125import_static_tuple_c()
121126
122cdef void* _my_memrchr(void *s, int c, size_t n): # cannot_raise127cdef void* _my_memrchr(void *s, int c, size_t n): # cannot_raise
123 # memrchr seems to be a GNU extension, so we have to implement it ourselves128 # memrchr seems to be a GNU extension, so we have to implement it ourselves
@@ -610,7 +615,8 @@
610 :param new_block: This is to let the caller know that it needs to615 :param new_block: This is to let the caller know that it needs to
611 create a new directory block to store the next entry.616 create a new directory block to store the next entry.
612 """617 """
613 cdef object path_name_file_id_key618 cdef StaticTuple path_name_file_id_key
619 cdef StaticTuple tmp
614 cdef char *entry_size_cstr620 cdef char *entry_size_cstr
615 cdef unsigned long int entry_size621 cdef unsigned long int entry_size
616 cdef char* executable_cstr622 cdef char* executable_cstr
@@ -650,10 +656,20 @@
650 # Build up the key that will be used.656 # Build up the key that will be used.
651 # By using <object>(void *) Pyrex will automatically handle the657 # By using <object>(void *) Pyrex will automatically handle the
652 # Py_INCREF that we need.658 # Py_INCREF that we need.
653 path_name_file_id_key = (<object>p_current_dirname[0],659 cur_dirname = <object>p_current_dirname[0]
654 self.get_next_str(),660 # Use StaticTuple_New to pre-allocate, rather than creating a regular
655 self.get_next_str(),661 # tuple and passing it to the StaticTuple constructor.
656 )662 # path_name_file_id_key = StaticTuple(<object>p_current_dirname[0],
663 # self.get_next_str(),
664 # self.get_next_str(),
665 # )
666 tmp = StaticTuple_New(3)
667 Py_INCREF(cur_dirname); StaticTuple_SET_ITEM(tmp, 0, cur_dirname)
668 cur_basename = self.get_next_str()
669 cur_file_id = self.get_next_str()
670 Py_INCREF(cur_basename); StaticTuple_SET_ITEM(tmp, 1, cur_basename)
671 Py_INCREF(cur_file_id); StaticTuple_SET_ITEM(tmp, 2, cur_file_id)
672 path_name_file_id_key = tmp
657673
658 # Parse all of the per-tree information. current has the information in674 # Parse all of the per-tree information. current has the information in
659 # the same location as parent trees. The only difference is that 'info'675 # the same location as parent trees. The only difference is that 'info'
@@ -677,7 +693,20 @@
677 executable_cstr = self.get_next(&cur_size)693 executable_cstr = self.get_next(&cur_size)
678 is_executable = (executable_cstr[0] == c'y')694 is_executable = (executable_cstr[0] == c'y')
679 info = self.get_next_str()695 info = self.get_next_str()
680 PyList_Append(trees, (696 # TODO: If we want to use StaticTuple_New here we need to be pretty
697 # careful. We are relying on a bit of Pyrex
698 # automatic-conversion from 'int' to PyInt, and that doesn't
699 # play well with the StaticTuple_SET_ITEM macro.
700 # Timing doesn't (yet) show a worthwile improvement in speed
701 # versus complexity and maintainability.
702 # tmp = StaticTuple_New(5)
703 # Py_INCREF(minikind); StaticTuple_SET_ITEM(tmp, 0, minikind)
704 # Py_INCREF(fingerprint); StaticTuple_SET_ITEM(tmp, 1, fingerprint)
705 # Py_INCREF(entry_size); StaticTuple_SET_ITEM(tmp, 2, entry_size)
706 # Py_INCREF(is_executable); StaticTuple_SET_ITEM(tmp, 3, is_executable)
707 # Py_INCREF(info); StaticTuple_SET_ITEM(tmp, 4, info)
708 # PyList_Append(trees, tmp)
709 PyList_Append(trees, StaticTuple(
681 minikind, # minikind710 minikind, # minikind
682 fingerprint, # fingerprint711 fingerprint, # fingerprint
683 entry_size, # size712 entry_size, # size
684713
=== modified file 'bzrlib/_groupcompress_pyx.pyx'
--- bzrlib/_groupcompress_pyx.pyx 2010-02-17 17:11:16 +0000
+++ bzrlib/_groupcompress_pyx.pyx 2011-02-09 08:08:20 +0000
@@ -22,6 +22,8 @@
2222
2323
24cdef extern from "Python.h":24cdef extern from "Python.h":
25 ctypedef struct PyObject:
26 pass
25 ctypedef int Py_ssize_t # Required for older pyrex versions27 ctypedef int Py_ssize_t # Required for older pyrex versions
26 int PyString_CheckExact(object)28 int PyString_CheckExact(object)
27 char * PyString_AS_STRING(object)29 char * PyString_AS_STRING(object)
@@ -53,6 +55,7 @@
53 unsigned long *delta_size, unsigned long max_delta_size) nogil55 unsigned long *delta_size, unsigned long max_delta_size) nogil
54 unsigned long get_delta_hdr_size(unsigned char **datap,56 unsigned long get_delta_hdr_size(unsigned char **datap,
55 unsigned char *top) nogil57 unsigned char *top) nogil
58 unsigned long sizeof_delta_index(delta_index *index)
56 Py_ssize_t DELTA_SIZE_MIN59 Py_ssize_t DELTA_SIZE_MIN
5760
5861
@@ -91,8 +94,8 @@
91 cdef readonly object _sources94 cdef readonly object _sources
92 cdef source_info *_source_infos95 cdef source_info *_source_infos
93 cdef delta_index *_index96 cdef delta_index *_index
97 cdef public unsigned long _source_offset
94 cdef readonly unsigned int _max_num_sources98 cdef readonly unsigned int _max_num_sources
95 cdef public unsigned long _source_offset
9699
97 def __init__(self, source=None):100 def __init__(self, source=None):
98 self._sources = []101 self._sources = []
@@ -105,6 +108,22 @@
105 if source is not None:108 if source is not None:
106 self.add_source(source, 0)109 self.add_source(source, 0)
107110
111 def __sizeof__(self):
112 # We want to track the _source_infos allocations, but the referenced
113 # void* are actually tracked in _sources itself.
114 # XXX: Cython is capable of doing sizeof(class) and returning the size
115 # of the underlying struct. Pyrex (<= 0.9.9) refuses, so we need
116 # to do it manually. *sigh* Note that we might get it wrong
117 # because of alignment issues.
118 cdef Py_ssize_t size
119 # PyObject start, vtable *, 3 object pointers, 2 C ints
120 size = ((sizeof(PyObject) + sizeof(void*) + 3*sizeof(PyObject*)
121 + sizeof(unsigned long)
122 + sizeof(unsigned int))
123 + (sizeof(source_info) * self._max_num_sources)
124 + sizeof_delta_index(self._index))
125 return size
126
108 def __repr__(self):127 def __repr__(self):
109 return '%s(%d, %d)' % (self.__class__.__name__,128 return '%s(%d, %d)' % (self.__class__.__name__,
110 len(self._sources), self._source_offset)129 len(self._sources), self._source_offset)
111130
=== modified file 'bzrlib/_simple_set_pyx.pyx'
--- bzrlib/_simple_set_pyx.pyx 2010-02-17 17:11:16 +0000
+++ bzrlib/_simple_set_pyx.pyx 2011-02-09 08:08:20 +0000
@@ -115,6 +115,20 @@
115 raise MemoryError()115 raise MemoryError()
116 memset(self._table, 0, n_bytes)116 memset(self._table, 0, n_bytes)
117117
118 def __sizeof__(self):
119 # Note: Pyrex doesn't allow sizeof(class) so we re-implement it here.
120 # Bits are:
121 # 1: PyObject
122 # 2: vtable *
123 # 3: 3 Py_ssize_t
124 # 4: PyObject**
125 # Note that we might get alignment, etc, wrong, but at least this is
126 # better than no estimate at all
127 # return sizeof(SimpleSet) + (self._mask + 1) * (sizeof(PyObject*))
128 return (sizeof(PyObject) + sizeof(void*)
129 + 3*sizeof(Py_ssize_t) + sizeof(PyObject**)
130 + (self._mask + 1) * sizeof(PyObject*))
131
118 def __dealloc__(self):132 def __dealloc__(self):
119 if self._table != NULL:133 if self._table != NULL:
120 PyMem_Free(self._table)134 PyMem_Free(self._table)
121135
=== modified file 'bzrlib/_static_tuple_c.pxd'
--- bzrlib/_static_tuple_c.pxd 2010-05-11 14:13:31 +0000
+++ bzrlib/_static_tuple_c.pxd 2011-02-09 08:08:20 +0000
@@ -33,6 +33,7 @@
33 int import_static_tuple_c() except -133 int import_static_tuple_c() except -1
34 StaticTuple StaticTuple_New(Py_ssize_t)34 StaticTuple StaticTuple_New(Py_ssize_t)
35 StaticTuple StaticTuple_Intern(StaticTuple)35 StaticTuple StaticTuple_Intern(StaticTuple)
36 StaticTuple StaticTuple_FromSequence(object)
3637
37 # Steals a reference and val must be a valid type, no checking is done38 # Steals a reference and val must be a valid type, no checking is done
38 void StaticTuple_SET_ITEM(StaticTuple key, Py_ssize_t offset, object val)39 void StaticTuple_SET_ITEM(StaticTuple key, Py_ssize_t offset, object val)
3940
=== modified file 'bzrlib/branch.py'
--- bzrlib/branch.py 2010-08-13 07:32:06 +0000
+++ bzrlib/branch.py 2011-02-09 08:08:20 +0000
@@ -1,4 +1,4 @@
1# Copyright (C) 2005-2010 Canonical Ltd1# Copyright (C) 2005-2011 Canonical Ltd
2#2#
3# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -25,8 +25,11 @@
25 bzrdir,25 bzrdir,
26 cache_utf8,26 cache_utf8,
27 config as _mod_config,27 config as _mod_config,
28 controldir,
28 debug,29 debug,
29 errors,30 errors,
31 fetch,
32 graph as _mod_graph,
30 lockdir,33 lockdir,
31 lockable_files,34 lockable_files,
32 remote,35 remote,
@@ -64,7 +67,7 @@
64BZR_BRANCH_FORMAT_6 = "Bazaar Branch Format 6 (bzr 0.15)\n"67BZR_BRANCH_FORMAT_6 = "Bazaar Branch Format 6 (bzr 0.15)\n"
6568
6669
67class Branch(bzrdir.ControlComponent):70class Branch(controldir.ControlComponent):
68 """Branch holding a history of revisions.71 """Branch holding a history of revisions.
6972
70 :ivar base:73 :ivar base:
@@ -91,6 +94,7 @@
91 self._revision_id_to_revno_cache = None94 self._revision_id_to_revno_cache = None
92 self._partial_revision_id_to_revno_cache = {}95 self._partial_revision_id_to_revno_cache = {}
93 self._partial_revision_history_cache = []96 self._partial_revision_history_cache = []
97 self._tags_bytes = None
94 self._last_revision_info_cache = None98 self._last_revision_info_cache = None
95 self._merge_sorted_revisions_cache = None99 self._merge_sorted_revisions_cache = None
96 self._open_hook()100 self._open_hook()
@@ -103,6 +107,13 @@
103107
104 def _activate_fallback_location(self, url):108 def _activate_fallback_location(self, url):
105 """Activate the branch/repository from url as a fallback repository."""109 """Activate the branch/repository from url as a fallback repository."""
110 for existing_fallback_repo in self.repository._fallback_repositories:
111 if existing_fallback_repo.user_url == url:
112 # This fallback is already configured. This probably only
113 # happens because BzrDir.sprout is a horrible mess. To avoid
114 # confusing _unstack we don't add this a second time.
115 mutter('duplicate activation of fallback %r on %r', url, self)
116 return
106 repo = self._get_fallback_repository(url)117 repo = self._get_fallback_repository(url)
107 if repo.has_same_location(self.repository):118 if repo.has_same_location(self.repository):
108 raise errors.UnstackableLocationError(self.user_url, url)119 raise errors.UnstackableLocationError(self.user_url, url)
@@ -226,6 +237,7 @@
226 possible_transports=[self.bzrdir.root_transport])237 possible_transports=[self.bzrdir.root_transport])
227 return a_branch.repository238 return a_branch.repository
228239
240 @needs_read_lock
229 def _get_tags_bytes(self):241 def _get_tags_bytes(self):
230 """Get the bytes of a serialised tags dict.242 """Get the bytes of a serialised tags dict.
231243
@@ -238,7 +250,9 @@
238 :return: The bytes of the tags file.250 :return: The bytes of the tags file.
239 :seealso: Branch._set_tags_bytes.251 :seealso: Branch._set_tags_bytes.
240 """252 """
241 return self._transport.get_bytes('tags')253 if self._tags_bytes is None:
254 self._tags_bytes = self._transport.get_bytes('tags')
255 return self._tags_bytes
242256
243 def _get_nick(self, local=False, possible_transports=None):257 def _get_nick(self, local=False, possible_transports=None):
244 config = self.get_config()258 config = self.get_config()
@@ -648,15 +662,22 @@
648 raise errors.UnsupportedOperation(self.get_reference_info, self)662 raise errors.UnsupportedOperation(self.get_reference_info, self)
649663
650 @needs_write_lock664 @needs_write_lock
651 def fetch(self, from_branch, last_revision=None, pb=None):665 def fetch(self, from_branch, last_revision=None, pb=None, fetch_spec=None):
652 """Copy revisions from from_branch into this branch.666 """Copy revisions from from_branch into this branch.
653667
654 :param from_branch: Where to copy from.668 :param from_branch: Where to copy from.
655 :param last_revision: What revision to stop at (None for at the end669 :param last_revision: What revision to stop at (None for at the end
656 of the branch.670 of the branch.
657 :param pb: An optional progress bar to use.671 :param pb: An optional progress bar to use.
672 :param fetch_spec: If specified, a SearchResult or
673 PendingAncestryResult that describes which revisions to copy. This
674 allows copying multiple heads at once. Mutually exclusive with
675 last_revision.
658 :return: None676 :return: None
659 """677 """
678 if fetch_spec is not None and last_revision is not None:
679 raise AssertionError(
680 "fetch_spec and last_revision are mutually exclusive.")
660 if self.base == from_branch.base:681 if self.base == from_branch.base:
661 return (0, [])682 return (0, [])
662 if pb is not None:683 if pb is not None:
@@ -665,12 +686,12 @@
665 % "pb parameter to fetch()")686 % "pb parameter to fetch()")
666 from_branch.lock_read()687 from_branch.lock_read()
667 try:688 try:
668 if last_revision is None:689 if last_revision is None and fetch_spec is None:
669 last_revision = from_branch.last_revision()690 last_revision = from_branch.last_revision()
670 last_revision = _mod_revision.ensure_null(last_revision)691 last_revision = _mod_revision.ensure_null(last_revision)
671 return self.repository.fetch(from_branch.repository,692 return self.repository.fetch(from_branch.repository,
672 revision_id=last_revision,693 revision_id=last_revision,
673 pb=pb)694 pb=pb, fetch_spec=fetch_spec)
674 finally:695 finally:
675 from_branch.unlock()696 from_branch.unlock()
676697
@@ -804,7 +825,8 @@
804 old_repository = self.repository825 old_repository = self.repository
805 if len(old_repository._fallback_repositories) != 1:826 if len(old_repository._fallback_repositories) != 1:
806 raise AssertionError("can't cope with fallback repositories "827 raise AssertionError("can't cope with fallback repositories "
807 "of %r" % (self.repository,))828 "of %r (fallbacks: %r)" % (old_repository,
829 old_repository._fallback_repositories))
808 # Open the new repository object.830 # Open the new repository object.
809 # Repositories don't offer an interface to remove fallback831 # Repositories don't offer an interface to remove fallback
810 # repositories today; take the conceptually simpler option and just832 # repositories today; take the conceptually simpler option and just
@@ -875,8 +897,12 @@
875897
876 :seealso: Branch._get_tags_bytes.898 :seealso: Branch._get_tags_bytes.
877 """899 """
878 return _run_with_write_locked_target(self, self._transport.put_bytes,900 return _run_with_write_locked_target(self, self._set_tags_bytes_locked,
879 'tags', bytes)901 bytes)
902
903 def _set_tags_bytes_locked(self, bytes):
904 self._tags_bytes = bytes
905 return self._transport.put_bytes('tags', bytes)
880906
881 def _cache_revision_history(self, rev_history):907 def _cache_revision_history(self, rev_history):
882 """Set the cached revision history to rev_history.908 """Set the cached revision history to rev_history.
@@ -912,6 +938,7 @@
912 self._merge_sorted_revisions_cache = None938 self._merge_sorted_revisions_cache = None
913 self._partial_revision_history_cache = []939 self._partial_revision_history_cache = []
914 self._partial_revision_id_to_revno_cache = {}940 self._partial_revision_id_to_revno_cache = {}
941 self._tags_bytes = None
915942
916 def _gen_revision_history(self):943 def _gen_revision_history(self):
917 """Return sequence of revision hashes on to this branch.944 """Return sequence of revision hashes on to this branch.
@@ -1002,7 +1029,7 @@
1002 return other_history[self_len:stop_revision]1029 return other_history[self_len:stop_revision]
10031030
1004 def update_revisions(self, other, stop_revision=None, overwrite=False,1031 def update_revisions(self, other, stop_revision=None, overwrite=False,
1005 graph=None):1032 graph=None, fetch_tags=True):
1006 """Pull in new perfect-fit revisions.1033 """Pull in new perfect-fit revisions.
10071034
1008 :param other: Another Branch to pull from1035 :param other: Another Branch to pull from
@@ -1011,17 +1038,17 @@
1011 to see if it is a proper descendant.1038 to see if it is a proper descendant.
1012 :param graph: A Graph object that can be used to query history1039 :param graph: A Graph object that can be used to query history
1013 information. This can be None.1040 information. This can be None.
1041 :param fetch_tags: Flag that specifies if tags from other should be
1042 fetched too.
1014 :return: None1043 :return: None
1015 """1044 """
1016 return InterBranch.get(other, self).update_revisions(stop_revision,1045 return InterBranch.get(other, self).update_revisions(stop_revision,
1017 overwrite, graph)1046 overwrite, graph, fetch_tags=fetch_tags)
10181047
1048 @deprecated_method(deprecated_in((2, 4, 0)))
1019 def import_last_revision_info(self, source_repo, revno, revid):1049 def import_last_revision_info(self, source_repo, revno, revid):
1020 """Set the last revision info, importing from another repo if necessary.1050 """Set the last revision info, importing from another repo if necessary.
10211051
1022 This is used by the bound branch code to upload a revision to
1023 the master branch first before updating the tip of the local branch.
1024
1025 :param source_repo: Source repository to optionally fetch from1052 :param source_repo: Source repository to optionally fetch from
1026 :param revno: Revision number of the new tip1053 :param revno: Revision number of the new tip
1027 :param revid: Revision id of the new tip1054 :param revid: Revision id of the new tip
@@ -1030,6 +1057,28 @@
1030 self.repository.fetch(source_repo, revision_id=revid)1057 self.repository.fetch(source_repo, revision_id=revid)
1031 self.set_last_revision_info(revno, revid)1058 self.set_last_revision_info(revno, revid)
10321059
1060 def import_last_revision_info_and_tags(self, source, revno, revid):
1061 """Set the last revision info, importing from another repo if necessary.
1062
1063 This is used by the bound branch code to upload a revision to
1064 the master branch first before updating the tip of the local branch.
1065 Revisions referenced by source's tags are also transferred.
1066
1067 :param source: Source branch to optionally fetch from
1068 :param revno: Revision number of the new tip
1069 :param revid: Revision id of the new tip
1070 """
1071 if not self.repository.has_same_location(source.repository):
1072 try:
1073 tags_to_fetch = set(source.tags.get_reverse_tag_dict())
1074 except errors.TagsNotSupported:
1075 tags_to_fetch = set()
1076 fetch_spec = _mod_graph.NotInOtherForRevs(self.repository,
1077 source.repository, [revid],
1078 if_present_ids=tags_to_fetch).execute()
1079 self.repository.fetch(source.repository, fetch_spec=fetch_spec)
1080 self.set_last_revision_info(revno, revid)
1081
1033 def revision_id_to_revno(self, revision_id):1082 def revision_id_to_revno(self, revision_id):
1034 """Given a revision id, return its revno"""1083 """Given a revision id, return its revno"""
1035 if _mod_revision.is_null(revision_id):1084 if _mod_revision.is_null(revision_id):
@@ -1256,7 +1305,8 @@
1256 return result1305 return result
12571306
1258 @needs_read_lock1307 @needs_read_lock
1259 def sprout(self, to_bzrdir, revision_id=None, repository_policy=None):1308 def sprout(self, to_bzrdir, revision_id=None, repository_policy=None,
1309 repository=None):
1260 """Create a new line of development from the branch, into to_bzrdir.1310 """Create a new line of development from the branch, into to_bzrdir.
12611311
1262 to_bzrdir controls the branch format.1312 to_bzrdir controls the branch format.
@@ -1267,7 +1317,7 @@
1267 if (repository_policy is not None and1317 if (repository_policy is not None and
1268 repository_policy.requires_stacking()):1318 repository_policy.requires_stacking()):
1269 to_bzrdir._format.require_stacking(_skip_repo=True)1319 to_bzrdir._format.require_stacking(_skip_repo=True)
1270 result = to_bzrdir.create_branch()1320 result = to_bzrdir.create_branch(repository=repository)
1271 result.lock_write()1321 result.lock_write()
1272 try:1322 try:
1273 if repository_policy is not None:1323 if repository_policy is not None:
@@ -1361,17 +1411,13 @@
1361 """Return the most suitable metadir for a checkout of this branch.1411 """Return the most suitable metadir for a checkout of this branch.
1362 Weaves are used if this branch's repository uses weaves.1412 Weaves are used if this branch's repository uses weaves.
1363 """1413 """
1364 if isinstance(self.bzrdir, bzrdir.BzrDirPreSplitOut):1414 format = self.repository.bzrdir.checkout_metadir()
1365 from bzrlib.repofmt import weaverepo1415 format.set_branch_format(self._format)
1366 format = bzrdir.BzrDirMetaFormat1()
1367 format.repository_format = weaverepo.RepositoryFormat7()
1368 else:
1369 format = self.repository.bzrdir.checkout_metadir()
1370 format.set_branch_format(self._format)
1371 return format1416 return format
13721417
1373 def create_clone_on_transport(self, to_transport, revision_id=None,1418 def create_clone_on_transport(self, to_transport, revision_id=None,
1374 stacked_on=None, create_prefix=False, use_existing_dir=False):1419 stacked_on=None, create_prefix=False, use_existing_dir=False,
1420 no_tree=None):
1375 """Create a clone of this branch and its bzrdir.1421 """Create a clone of this branch and its bzrdir.
13761422
1377 :param to_transport: The transport to clone onto.1423 :param to_transport: The transport to clone onto.
@@ -1390,7 +1436,8 @@
1390 revision_id = self.last_revision()1436 revision_id = self.last_revision()
1391 dir_to = self.bzrdir.clone_on_transport(to_transport,1437 dir_to = self.bzrdir.clone_on_transport(to_transport,
1392 revision_id=revision_id, stacked_on=stacked_on,1438 revision_id=revision_id, stacked_on=stacked_on,
1393 create_prefix=create_prefix, use_existing_dir=use_existing_dir)1439 create_prefix=create_prefix, use_existing_dir=use_existing_dir,
1440 no_tree=no_tree)
1394 return dir_to.open_branch()1441 return dir_to.open_branch()
13951442
1396 def create_checkout(self, to_location, revision_id=None,1443 def create_checkout(self, to_location, revision_id=None,
@@ -1521,7 +1568,7 @@
1521 * an open routine.1568 * an open routine.
15221569
1523 Formats are placed in an dict by their format string for reference1570 Formats are placed in an dict by their format string for reference
1524 during branch opening. Its not required that these be instances, they1571 during branch opening. It's not required that these be instances, they
1525 can be classes themselves with class methods - it simply depends on1572 can be classes themselves with class methods - it simply depends on
1526 whether state is needed for a given format or not.1573 whether state is needed for a given format or not.
15271574
@@ -1536,6 +1583,9 @@
1536 _formats = {}1583 _formats = {}
1537 """The known formats."""1584 """The known formats."""
15381585
1586 _extra_formats = []
1587 """Extra formats that can not be part of a metadir."""
1588
1539 can_set_append_revisions_only = True1589 can_set_append_revisions_only = True
15401590
1541 def __eq__(self, other):1591 def __eq__(self, other):
@@ -1576,7 +1626,7 @@
1576 if isinstance(fmt, MetaDirBranchFormatFactory):1626 if isinstance(fmt, MetaDirBranchFormatFactory):
1577 fmt = fmt()1627 fmt = fmt()
1578 result.append(fmt)1628 result.append(fmt)
1579 return result1629 return result + klass._extra_formats
15801630
1581 def get_reference(self, a_bzrdir, name=None):1631 def get_reference(self, a_bzrdir, name=None):
1582 """Get the target reference of the branch in a_bzrdir.1632 """Get the target reference of the branch in a_bzrdir.
@@ -1622,7 +1672,8 @@
1622 hook(params)1672 hook(params)
16231673
1624 def _initialize_helper(self, a_bzrdir, utf8_files, name=None,1674 def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1625 lock_type='metadir', set_format=True):1675 repository=None, lock_type='metadir',
1676 set_format=True):
1626 """Initialize a branch in a bzrdir, with specified files1677 """Initialize a branch in a bzrdir, with specified files
16271678
1628 :param a_bzrdir: The bzrdir to initialize the branch in1679 :param a_bzrdir: The bzrdir to initialize the branch in
@@ -1662,11 +1713,12 @@
1662 finally:1713 finally:
1663 if lock_taken:1714 if lock_taken:
1664 control_files.unlock()1715 control_files.unlock()
1665 branch = self.open(a_bzrdir, name, _found=True)1716 branch = self.open(a_bzrdir, name, _found=True,
1717 found_repository=repository)
1666 self._run_post_branch_init_hooks(a_bzrdir, name, branch)1718 self._run_post_branch_init_hooks(a_bzrdir, name, branch)
1667 return branch1719 return branch
16681720
1669 def initialize(self, a_bzrdir, name=None):1721 def initialize(self, a_bzrdir, name=None, repository=None):
1670 """Create a branch of this format in a_bzrdir.1722 """Create a branch of this format in a_bzrdir.
1671 1723
1672 :param name: Name of the colocated branch to create.1724 :param name: Name of the colocated branch to create.
@@ -1706,7 +1758,8 @@
1706 """1758 """
1707 raise NotImplementedError(self.network_name)1759 raise NotImplementedError(self.network_name)
17081760
1709 def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):1761 def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
1762 found_repository=None):
1710 """Return the branch object for a_bzrdir1763 """Return the branch object for a_bzrdir
17111764
1712 :param a_bzrdir: A BzrDir that contains a branch.1765 :param a_bzrdir: A BzrDir that contains a branch.
@@ -1719,6 +1772,17 @@
1719 raise NotImplementedError(self.open)1772 raise NotImplementedError(self.open)
17201773
1721 @classmethod1774 @classmethod
1775 def register_extra_format(klass, format):
1776 """Register a branch format that can not be part of a metadir.
1777
1778 This is mainly useful to allow custom branch formats, such as
1779 older Bazaar formats and foreign formats, to be tested
1780 """
1781 klass._extra_formats.append(format)
1782 network_format_registry.register(
1783 format.network_name(), format.__class__)
1784
1785 @classmethod
1722 def register_format(klass, format):1786 def register_format(klass, format):
1723 """Register a metadir format.1787 """Register a metadir format.
1724 1788
@@ -1750,6 +1814,10 @@
1750 def unregister_format(klass, format):1814 def unregister_format(klass, format):
1751 del klass._formats[format.get_format_string()]1815 del klass._formats[format.get_format_string()]
17521816
1817 @classmethod
1818 def unregister_extra_format(klass, format):
1819 klass._extra_formats.remove(format)
1820
1753 def __str__(self):1821 def __str__(self):
1754 return self.get_format_description().rstrip()1822 return self.get_format_description().rstrip()
17551823
@@ -1818,7 +1886,7 @@
1818 "with a bzrlib.branch.PullResult object and only runs in the "1886 "with a bzrlib.branch.PullResult object and only runs in the "
1819 "bzr client.", (0, 15), None))1887 "bzr client.", (0, 15), None))
1820 self.create_hook(HookPoint('pre_commit',1888 self.create_hook(HookPoint('pre_commit',
1821 "Called after a commit is calculated but before it is is "1889 "Called after a commit is calculated but before it is "
1822 "completed. pre_commit is called with (local, master, old_revno, "1890 "completed. pre_commit is called with (local, master, old_revno, "
1823 "old_revid, future_revno, future_revid, tree_delta, future_tree"1891 "old_revid, future_revno, future_revid, tree_delta, future_tree"
1824 "). old_revid is NULL_REVISION for the first commit to a branch, "1892 "). old_revid is NULL_REVISION for the first commit to a branch, "
@@ -2006,8 +2074,11 @@
2006 """See BranchFormat.get_format_description()."""2074 """See BranchFormat.get_format_description()."""
2007 return "Branch format 4"2075 return "Branch format 4"
20082076
2009 def initialize(self, a_bzrdir, name=None):2077 def initialize(self, a_bzrdir, name=None, repository=None):
2010 """Create a branch of this format in a_bzrdir."""2078 """Create a branch of this format in a_bzrdir."""
2079 if repository is not None:
2080 raise NotImplementedError(
2081 "initialize(repository=<not None>) on %r" % (self,))
2011 utf8_files = [('revision-history', ''),2082 utf8_files = [('revision-history', ''),
2012 ('branch-name', ''),2083 ('branch-name', ''),
2013 ]2084 ]
@@ -2022,16 +2093,19 @@
2022 """The network name for this format is the control dirs disk label."""2093 """The network name for this format is the control dirs disk label."""
2023 return self._matchingbzrdir.get_format_string()2094 return self._matchingbzrdir.get_format_string()
20242095
2025 def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):2096 def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
2097 found_repository=None):
2026 """See BranchFormat.open()."""2098 """See BranchFormat.open()."""
2027 if not _found:2099 if not _found:
2028 # we are being called directly and must probe.2100 # we are being called directly and must probe.
2029 raise NotImplementedError2101 raise NotImplementedError
2030 return BzrBranch(_format=self,2102 if found_repository is None:
2103 found_repository = a_bzrdir.open_repository()
2104 return BzrBranchPreSplitOut(_format=self,
2031 _control_files=a_bzrdir._control_files,2105 _control_files=a_bzrdir._control_files,
2032 a_bzrdir=a_bzrdir,2106 a_bzrdir=a_bzrdir,
2033 name=name,2107 name=name,
2034 _repository=a_bzrdir.open_repository())2108 _repository=found_repository)
20352109
2036 def __str__(self):2110 def __str__(self):
2037 return "Bazaar-NG branch format 4"2111 return "Bazaar-NG branch format 4"
@@ -2051,7 +2125,8 @@
2051 """2125 """
2052 return self.get_format_string()2126 return self.get_format_string()
20532127
2054 def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False):2128 def open(self, a_bzrdir, name=None, _found=False, ignore_fallbacks=False,
2129 found_repository=None):
2055 """See BranchFormat.open()."""2130 """See BranchFormat.open()."""
2056 if not _found:2131 if not _found:
2057 format = BranchFormat.find_format(a_bzrdir, name=name)2132 format = BranchFormat.find_format(a_bzrdir, name=name)
@@ -2062,11 +2137,13 @@
2062 try:2137 try:
2063 control_files = lockable_files.LockableFiles(transport, 'lock',2138 control_files = lockable_files.LockableFiles(transport, 'lock',
2064 lockdir.LockDir)2139 lockdir.LockDir)
2140 if found_repository is None:
2141 found_repository = a_bzrdir.find_repository()
2065 return self._branch_class()(_format=self,2142 return self._branch_class()(_format=self,
2066 _control_files=control_files,2143 _control_files=control_files,
2067 name=name,2144 name=name,
2068 a_bzrdir=a_bzrdir,2145 a_bzrdir=a_bzrdir,
2069 _repository=a_bzrdir.find_repository(),2146 _repository=found_repository,
2070 ignore_fallbacks=ignore_fallbacks)2147 ignore_fallbacks=ignore_fallbacks)
2071 except errors.NoSuchFile:2148 except errors.NoSuchFile:
2072 raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)2149 raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
@@ -2104,12 +2181,12 @@
2104 """See BranchFormat.get_format_description()."""2181 """See BranchFormat.get_format_description()."""
2105 return "Branch format 5"2182 return "Branch format 5"
21062183
2107 def initialize(self, a_bzrdir, name=None):2184 def initialize(self, a_bzrdir, name=None, repository=None):
2108 """Create a branch of this format in a_bzrdir."""2185 """Create a branch of this format in a_bzrdir."""
2109 utf8_files = [('revision-history', ''),2186 utf8_files = [('revision-history', ''),
2110 ('branch-name', ''),2187 ('branch-name', ''),
2111 ]2188 ]
2112 return self._initialize_helper(a_bzrdir, utf8_files, name)2189 return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
21132190
2114 def supports_tags(self):2191 def supports_tags(self):
2115 return False2192 return False
@@ -2137,13 +2214,13 @@
2137 """See BranchFormat.get_format_description()."""2214 """See BranchFormat.get_format_description()."""
2138 return "Branch format 6"2215 return "Branch format 6"
21392216
2140 def initialize(self, a_bzrdir, name=None):2217 def initialize(self, a_bzrdir, name=None, repository=None):
2141 """Create a branch of this format in a_bzrdir."""2218 """Create a branch of this format in a_bzrdir."""
2142 utf8_files = [('last-revision', '0 null:\n'),2219 utf8_files = [('last-revision', '0 null:\n'),
2143 ('branch.conf', ''),2220 ('branch.conf', ''),
2144 ('tags', ''),2221 ('tags', ''),
2145 ]2222 ]
2146 return self._initialize_helper(a_bzrdir, utf8_files, name)2223 return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
21472224
2148 def make_tags(self, branch):2225 def make_tags(self, branch):
2149 """See bzrlib.branch.BranchFormat.make_tags()."""2226 """See bzrlib.branch.BranchFormat.make_tags()."""
@@ -2167,14 +2244,14 @@
2167 """See BranchFormat.get_format_description()."""2244 """See BranchFormat.get_format_description()."""
2168 return "Branch format 8"2245 return "Branch format 8"
21692246
2170 def initialize(self, a_bzrdir, name=None):2247 def initialize(self, a_bzrdir, name=None, repository=None):
2171 """Create a branch of this format in a_bzrdir."""2248 """Create a branch of this format in a_bzrdir."""
2172 utf8_files = [('last-revision', '0 null:\n'),2249 utf8_files = [('last-revision', '0 null:\n'),
2173 ('branch.conf', ''),2250 ('branch.conf', ''),
2174 ('tags', ''),2251 ('tags', ''),
2175 ('references', '')2252 ('references', '')
2176 ]2253 ]
2177 return self._initialize_helper(a_bzrdir, utf8_files, name)2254 return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
21782255
2179 def __init__(self):2256 def __init__(self):
2180 super(BzrBranchFormat8, self).__init__()2257 super(BzrBranchFormat8, self).__init__()
@@ -2203,13 +2280,13 @@
2203 This format was introduced in bzr 1.6.2280 This format was introduced in bzr 1.6.
2204 """2281 """
22052282
2206 def initialize(self, a_bzrdir, name=None):2283 def initialize(self, a_bzrdir, name=None, repository=None):
2207 """Create a branch of this format in a_bzrdir."""2284 """Create a branch of this format in a_bzrdir."""
2208 utf8_files = [('last-revision', '0 null:\n'),2285 utf8_files = [('last-revision', '0 null:\n'),
2209 ('branch.conf', ''),2286 ('branch.conf', ''),
2210 ('tags', ''),2287 ('tags', ''),
2211 ]2288 ]
2212 return self._initialize_helper(a_bzrdir, utf8_files, name)2289 return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
22132290
2214 def _branch_class(self):2291 def _branch_class(self):
2215 return BzrBranch72292 return BzrBranch7
@@ -2257,7 +2334,8 @@
2257 transport = a_bzrdir.get_branch_transport(None, name=name)2334 transport = a_bzrdir.get_branch_transport(None, name=name)
2258 location = transport.put_bytes('location', to_branch.base)2335 location = transport.put_bytes('location', to_branch.base)
22592336
2260 def initialize(self, a_bzrdir, name=None, target_branch=None):2337 def initialize(self, a_bzrdir, name=None, target_branch=None,
2338 repository=None):
2261 """Create a branch of this format in a_bzrdir."""2339 """Create a branch of this format in a_bzrdir."""
2262 if target_branch is None:2340 if target_branch is None:
2263 # this format does not implement branch itself, thus the implicit2341 # this format does not implement branch itself, thus the implicit
@@ -2291,7 +2369,8 @@
2291 return clone2369 return clone
22922370
2293 def open(self, a_bzrdir, name=None, _found=False, location=None,2371 def open(self, a_bzrdir, name=None, _found=False, location=None,
2294 possible_transports=None, ignore_fallbacks=False):2372 possible_transports=None, ignore_fallbacks=False,
2373 found_repository=None):
2295 """Return the branch that the branch reference in a_bzrdir points at.2374 """Return the branch that the branch reference in a_bzrdir points at.
22962375
2297 :param a_bzrdir: A BzrDir that contains a branch.2376 :param a_bzrdir: A BzrDir that contains a branch.
@@ -2349,10 +2428,7 @@
2349BranchFormat.register_format(__format7)2428BranchFormat.register_format(__format7)
2350BranchFormat.register_format(__format8)2429BranchFormat.register_format(__format8)
2351BranchFormat.set_default_format(__format7)2430BranchFormat.set_default_format(__format7)
2352_legacy_formats = [BzrBranchFormat4(),2431BranchFormat.register_extra_format(BzrBranchFormat4())
2353 ]
2354network_format_registry.register(
2355 _legacy_formats[0].network_name(), _legacy_formats[0].__class__)
23562432
23572433
2358class BranchWriteLockResult(LogicalLockResult):2434class BranchWriteLockResult(LogicalLockResult):
@@ -2634,7 +2710,7 @@
2634 result.target_branch = target2710 result.target_branch = target
2635 result.old_revno, result.old_revid = target.last_revision_info()2711 result.old_revno, result.old_revid = target.last_revision_info()
2636 self.update_references(target)2712 self.update_references(target)
2637 if result.old_revid != self.last_revision():2713 if result.old_revid != stop_revision:
2638 # We assume that during 'push' this repository is closer than2714 # We assume that during 'push' this repository is closer than
2639 # the target.2715 # the target.
2640 graph = self.repository.get_graph(target.repository)2716 graph = self.repository.get_graph(target.repository)
@@ -2663,6 +2739,19 @@
2663 mode=self.bzrdir._get_file_mode())2739 mode=self.bzrdir._get_file_mode())
26642740
26652741
2742class BzrBranchPreSplitOut(BzrBranch):
2743
2744 def _get_checkout_format(self):
2745 """Return the most suitable metadir for a checkout of this branch.
2746 Weaves are used if this branch's repository uses weaves.
2747 """
2748 from bzrlib.repofmt.weaverepo import RepositoryFormat7
2749 from bzrlib.bzrdir import BzrDirMetaFormat1
2750 format = BzrDirMetaFormat1()
2751 format.repository_format = RepositoryFormat7()
2752 return format
2753
2754
2666class BzrBranch5(BzrBranch):2755class BzrBranch5(BzrBranch):
2667 """A format 5 branch. This supports new features over plain branches.2756 """A format 5 branch. This supports new features over plain branches.
26682757
@@ -3102,8 +3191,12 @@
3102 :ivar tag_conflicts: A list of tag conflicts, see BasicTags.merge_to3191 :ivar tag_conflicts: A list of tag conflicts, see BasicTags.merge_to
3103 """3192 """
31043193
3194 @deprecated_method(deprecated_in((2, 3, 0)))
3105 def __int__(self):3195 def __int__(self):
3106 # DEPRECATED: pull used to return the change in revno3196 """Return the relative change in revno.
3197
3198 :deprecated: Use `new_revno` and `old_revno` instead.
3199 """
3107 return self.new_revno - self.old_revno3200 return self.new_revno - self.old_revno
31083201
3109 def report(self, to_file):3202 def report(self, to_file):
@@ -3134,8 +3227,12 @@
3134 target, otherwise it will be None.3227 target, otherwise it will be None.
3135 """3228 """
31363229
3230 @deprecated_method(deprecated_in((2, 3, 0)))
3137 def __int__(self):3231 def __int__(self):
3138 # DEPRECATED: push used to return the change in revno3232 """Return the relative change in revno.
3233
3234 :deprecated: Use `new_revno` and `old_revno` instead.
3235 """
3139 return self.new_revno - self.old_revno3236 return self.new_revno - self.old_revno
31403237
3141 def report(self, to_file):3238 def report(self, to_file):
@@ -3287,7 +3384,7 @@
32873384
3288 @needs_write_lock3385 @needs_write_lock
3289 def update_revisions(self, stop_revision=None, overwrite=False,3386 def update_revisions(self, stop_revision=None, overwrite=False,
3290 graph=None):3387 graph=None, fetch_tags=True):
3291 """Pull in new perfect-fit revisions.3388 """Pull in new perfect-fit revisions.
32923389
3293 :param stop_revision: Updated until the given revision3390 :param stop_revision: Updated until the given revision
@@ -3295,6 +3392,8 @@
3295 to see if it is a proper descendant.3392 to see if it is a proper descendant.
3296 :param graph: A Graph object that can be used to query history3393 :param graph: A Graph object that can be used to query history
3297 information. This can be None.3394 information. This can be None.
3395 :param fetch_tags: Flag that specifies if tags from source should be
3396 fetched too.
3298 :return: None3397 :return: None
3299 """3398 """
3300 raise NotImplementedError(self.update_revisions)3399 raise NotImplementedError(self.update_revisions)
@@ -3308,6 +3407,15 @@
3308 """3407 """
3309 raise NotImplementedError(self.push)3408 raise NotImplementedError(self.push)
33103409
3410 @needs_write_lock
3411 def copy_content_into(self, revision_id=None):
3412 """Copy the content of source into target
3413
3414 revision_id: if not None, the revision history in the new branch will
3415 be truncated to end with revision_id.
3416 """
3417 raise NotImplementedError(self.copy_content_into)
3418
33113419
3312class GenericInterBranch(InterBranch):3420class GenericInterBranch(InterBranch):
3313 """InterBranch implementation that uses public Branch functions."""3421 """InterBranch implementation that uses public Branch functions."""
@@ -3326,7 +3434,7 @@
3326 if isinstance(format, remote.RemoteBranchFormat):3434 if isinstance(format, remote.RemoteBranchFormat):
3327 format._ensure_real()3435 format._ensure_real()
3328 return format._custom_format3436 return format._custom_format
3329 return format 3437 return format
33303438
3331 @needs_write_lock3439 @needs_write_lock
3332 def copy_content_into(self, revision_id=None):3440 def copy_content_into(self, revision_id=None):
@@ -3349,7 +3457,7 @@
33493457
3350 @needs_write_lock3458 @needs_write_lock
3351 def update_revisions(self, stop_revision=None, overwrite=False,3459 def update_revisions(self, stop_revision=None, overwrite=False,
3352 graph=None):3460 graph=None, fetch_tags=True):
3353 """See InterBranch.update_revisions()."""3461 """See InterBranch.update_revisions()."""
3354 other_revno, other_last_revision = self.source.last_revision_info()3462 other_revno, other_last_revision = self.source.last_revision_info()
3355 stop_revno = None # unknown3463 stop_revno = None # unknown
@@ -3367,7 +3475,18 @@
3367 # case of having something to pull, and so that the check for3475 # case of having something to pull, and so that the check for
3368 # already merged can operate on the just fetched graph, which will3476 # already merged can operate on the just fetched graph, which will
3369 # be cached in memory.3477 # be cached in memory.
3370 self.target.fetch(self.source, stop_revision)3478 if fetch_tags:
3479 fetch_spec_factory = fetch.FetchSpecFactory()
3480 fetch_spec_factory.source_branch = self.source
3481 fetch_spec_factory.source_branch_stop_revision_id = stop_revision
3482 fetch_spec_factory.source_repo = self.source.repository
3483 fetch_spec_factory.target_repo = self.target.repository
3484 fetch_spec_factory.target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
3485 fetch_spec = fetch_spec_factory.make_fetch_spec()
3486 else:
3487 fetch_spec = _mod_graph.NotInOtherForRevs(self.target.repository,
3488 self.source.repository, revision_ids=[stop_revision]).execute()
3489 self.target.fetch(self.source, fetch_spec=fetch_spec)
3371 # Check to see if one is an ancestor of the other3490 # Check to see if one is an ancestor of the other
3372 if not overwrite:3491 if not overwrite:
3373 if graph is None:3492 if graph is None:
@@ -3401,7 +3520,8 @@
3401 if local and not bound_location:3520 if local and not bound_location:
3402 raise errors.LocalRequiresBoundBranch()3521 raise errors.LocalRequiresBoundBranch()
3403 master_branch = None3522 master_branch = None
3404 if not local and bound_location and self.source.user_url != bound_location:3523 source_is_master = (self.source.user_url == bound_location)
3524 if not local and bound_location and not source_is_master:
3405 # not pulling from master, so we need to update master.3525 # not pulling from master, so we need to update master.
3406 master_branch = self.target.get_master_branch(possible_transports)3526 master_branch = self.target.get_master_branch(possible_transports)
3407 master_branch.lock_write()3527 master_branch.lock_write()
@@ -3413,7 +3533,8 @@
3413 return self._pull(overwrite,3533 return self._pull(overwrite,
3414 stop_revision, _hook_master=master_branch,3534 stop_revision, _hook_master=master_branch,
3415 run_hooks=run_hooks,3535 run_hooks=run_hooks,
3416 _override_hook_target=_override_hook_target)3536 _override_hook_target=_override_hook_target,
3537 merge_tags_to_master=not source_is_master)
3417 finally:3538 finally:
3418 if master_branch:3539 if master_branch:
3419 master_branch.unlock()3540 master_branch.unlock()
@@ -3462,7 +3583,7 @@
3462 # push into the master from the source branch.3583 # push into the master from the source branch.
3463 self.source._basic_push(master_branch, overwrite, stop_revision)3584 self.source._basic_push(master_branch, overwrite, stop_revision)
3464 # and push into the target branch from the source. Note that we3585 # and push into the target branch from the source. Note that we
3465 # push from the source branch again, because its considered the3586 # push from the source branch again, because it's considered the
3466 # highest bandwidth repository.3587 # highest bandwidth repository.
3467 result = self.source._basic_push(self.target, overwrite,3588 result = self.source._basic_push(self.target, overwrite,
3468 stop_revision)3589 stop_revision)
@@ -3486,7 +3607,8 @@
34863607
3487 def _pull(self, overwrite=False, stop_revision=None,3608 def _pull(self, overwrite=False, stop_revision=None,
3488 possible_transports=None, _hook_master=None, run_hooks=True,3609 possible_transports=None, _hook_master=None, run_hooks=True,
3489 _override_hook_target=None, local=False):3610 _override_hook_target=None, local=False,
3611 merge_tags_to_master=True):
3490 """See Branch.pull.3612 """See Branch.pull.
34913613
3492 This function is the core worker, used by GenericInterBranch.pull to3614 This function is the core worker, used by GenericInterBranch.pull to
@@ -3527,7 +3649,7 @@
3527 # so a tags implementation that versions tags can only 3649 # so a tags implementation that versions tags can only
3528 # pull in the most recent changes. -- JRV200905063650 # pull in the most recent changes. -- JRV20090506
3529 result.tag_conflicts = self.source.tags.merge_to(self.target.tags,3651 result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3530 overwrite)3652 overwrite, ignore_master=not merge_tags_to_master)
3531 result.new_revno, result.new_revid = self.target.last_revision_info()3653 result.new_revno, result.new_revid = self.target.last_revision_info()
3532 if _hook_master:3654 if _hook_master:
3533 result.master_branch = _hook_master3655 result.master_branch = _hook_master
35343656
=== modified file 'bzrlib/branchbuilder.py'
--- bzrlib/branchbuilder.py 2010-02-27 12:27:33 +0000
+++ bzrlib/branchbuilder.py 2011-02-09 08:08:20 +0000
@@ -21,6 +21,7 @@
21 commit,21 commit,
22 errors,22 errors,
23 memorytree,23 memorytree,
24 revision,
24 )25 )
2526
2627
@@ -186,7 +187,10 @@
186 :return: The revision_id of the new commit187 :return: The revision_id of the new commit
187 """188 """
188 if parent_ids is not None:189 if parent_ids is not None:
189 base_id = parent_ids[0]190 if len(parent_ids) == 0:
191 base_id = revision.NULL_REVISION
192 else:
193 base_id = parent_ids[0]
190 if base_id != self._branch.last_revision():194 if base_id != self._branch.last_revision():
191 self._move_branch_pointer(base_id,195 self._move_branch_pointer(base_id,
192 allow_leftmost_as_ghost=allow_leftmost_as_ghost)196 allow_leftmost_as_ghost=allow_leftmost_as_ghost)
193197
=== modified file 'bzrlib/btree_index.py'
--- bzrlib/btree_index.py 2010-06-20 11:18:38 +0000
+++ bzrlib/btree_index.py 2011-02-09 08:08:20 +0000
@@ -602,10 +602,10 @@
602 """In memory index's have no known corruption at the moment."""602 """In memory index's have no known corruption at the moment."""
603603
604604
605class _LeafNode(object):605class _LeafNode(dict):
606 """A leaf node for a serialised B+Tree index."""606 """A leaf node for a serialised B+Tree index."""
607607
608 __slots__ = ('keys', 'min_key', 'max_key')608 __slots__ = ('min_key', 'max_key', '_keys')
609609
610 def __init__(self, bytes, key_length, ref_list_length):610 def __init__(self, bytes, key_length, ref_list_length):
611 """Parse bytes to create a leaf node object."""611 """Parse bytes to create a leaf node object."""
@@ -617,7 +617,20 @@
617 self.max_key = key_list[-1][0]617 self.max_key = key_list[-1][0]
618 else:618 else:
619 self.min_key = self.max_key = None619 self.min_key = self.max_key = None
620 self.keys = dict(key_list)620 super(_LeafNode, self).__init__(key_list)
621 self._keys = dict(self)
622
623 def all_items(self):
624 """Return a sorted list of (key, (value, refs)) items"""
625 items = self.items()
626 items.sort()
627 return items
628
629 def all_keys(self):
630 """Return a sorted list of all keys."""
631 keys = self.keys()
632 keys.sort()
633 return keys
621634
622635
623class _InternalNode(object):636class _InternalNode(object):
@@ -672,6 +685,7 @@
672 self._recommended_pages = self._compute_recommended_pages()685 self._recommended_pages = self._compute_recommended_pages()
673 self._root_node = None686 self._root_node = None
674 self._base_offset = offset687 self._base_offset = offset
688 self._leaf_factory = _LeafNode
675 # Default max size is 100,000 leave values689 # Default max size is 100,000 leave values
676 self._leaf_value_cache = None # lru_cache.LRUCache(100*1000)690 self._leaf_value_cache = None # lru_cache.LRUCache(100*1000)
677 if unlimited_cache:691 if unlimited_cache:
@@ -950,7 +964,7 @@
950 """Cache directly from key => value, skipping the btree."""964 """Cache directly from key => value, skipping the btree."""
951 if self._leaf_value_cache is not None:965 if self._leaf_value_cache is not None:
952 for node in nodes.itervalues():966 for node in nodes.itervalues():
953 for key, value in node.keys.iteritems():967 for key, value in node.all_items():
954 if key in self._leaf_value_cache:968 if key in self._leaf_value_cache:
955 # Don't add the rest of the keys, we've seen this node969 # Don't add the rest of the keys, we've seen this node
956 # before.970 # before.
@@ -980,10 +994,10 @@
980 if self._row_offsets[-1] == 1:994 if self._row_offsets[-1] == 1:
981 # There is only the root node, and we read that via key_count()995 # There is only the root node, and we read that via key_count()
982 if self.node_ref_lists:996 if self.node_ref_lists:
983 for key, (value, refs) in sorted(self._root_node.keys.items()):997 for key, (value, refs) in self._root_node.all_items():
984 yield (self, key, value, refs)998 yield (self, key, value, refs)
985 else:999 else:
986 for key, (value, refs) in sorted(self._root_node.keys.items()):1000 for key, (value, refs) in self._root_node.all_items():
987 yield (self, key, value)1001 yield (self, key, value)
988 return1002 return
989 start_of_leaves = self._row_offsets[-2]1003 start_of_leaves = self._row_offsets[-2]
@@ -999,11 +1013,11 @@
999 # for spilling index builds to disk.1013 # for spilling index builds to disk.
1000 if self.node_ref_lists:1014 if self.node_ref_lists:
1001 for _, node in nodes:1015 for _, node in nodes:
1002 for key, (value, refs) in sorted(node.keys.items()):1016 for key, (value, refs) in node.all_items():
1003 yield (self, key, value, refs)1017 yield (self, key, value, refs)
1004 else:1018 else:
1005 for _, node in nodes:1019 for _, node in nodes:
1006 for key, (value, refs) in sorted(node.keys.items()):1020 for key, (value, refs) in node.all_items():
1007 yield (self, key, value)1021 yield (self, key, value)
10081022
1009 @staticmethod1023 @staticmethod
@@ -1170,8 +1184,8 @@
1170 continue1184 continue
1171 node = nodes[node_index]1185 node = nodes[node_index]
1172 for next_sub_key in sub_keys:1186 for next_sub_key in sub_keys:
1173 if next_sub_key in node.keys:1187 if next_sub_key in node:
1174 value, refs = node.keys[next_sub_key]1188 value, refs = node[next_sub_key]
1175 if self.node_ref_lists:1189 if self.node_ref_lists:
1176 yield (self, next_sub_key, value, refs)1190 yield (self, next_sub_key, value, refs)
1177 else:1191 else:
@@ -1245,14 +1259,13 @@
1245 # sub_keys is all of the keys we are looking for that should exist1259 # sub_keys is all of the keys we are looking for that should exist
1246 # on this page, if they aren't here, then they won't be found1260 # on this page, if they aren't here, then they won't be found
1247 node = nodes[node_index]1261 node = nodes[node_index]
1248 node_keys = node.keys
1249 parents_to_check = set()1262 parents_to_check = set()
1250 for next_sub_key in sub_keys:1263 for next_sub_key in sub_keys:
1251 if next_sub_key not in node_keys:1264 if next_sub_key not in node:
1252 # This one is just not present in the index at all1265 # This one is just not present in the index at all
1253 missing_keys.add(next_sub_key)1266 missing_keys.add(next_sub_key)
1254 else:1267 else:
1255 value, refs = node_keys[next_sub_key]1268 value, refs = node[next_sub_key]
1256 parent_keys = refs[ref_list_num]1269 parent_keys = refs[ref_list_num]
1257 parent_map[next_sub_key] = parent_keys1270 parent_map[next_sub_key] = parent_keys
1258 parents_to_check.update(parent_keys)1271 parents_to_check.update(parent_keys)
@@ -1265,8 +1278,8 @@
1265 while parents_to_check:1278 while parents_to_check:
1266 next_parents_to_check = set()1279 next_parents_to_check = set()
1267 for key in parents_to_check:1280 for key in parents_to_check:
1268 if key in node_keys:1281 if key in node:
1269 value, refs = node_keys[key]1282 value, refs = node[key]
1270 parent_keys = refs[ref_list_num]1283 parent_keys = refs[ref_list_num]
1271 parent_map[key] = parent_keys1284 parent_map[key] = parent_keys
1272 next_parents_to_check.update(parent_keys)1285 next_parents_to_check.update(parent_keys)
@@ -1546,7 +1559,8 @@
1546 continue1559 continue
1547 bytes = zlib.decompress(data)1560 bytes = zlib.decompress(data)
1548 if bytes.startswith(_LEAF_FLAG):1561 if bytes.startswith(_LEAF_FLAG):
1549 node = _LeafNode(bytes, self._key_length, self.node_ref_lists)1562 node = self._leaf_factory(bytes, self._key_length,
1563 self.node_ref_lists)
1550 elif bytes.startswith(_INTERNAL_FLAG):1564 elif bytes.startswith(_INTERNAL_FLAG):
1551 node = _InternalNode(bytes)1565 node = _InternalNode(bytes)
1552 else:1566 else:
@@ -1571,8 +1585,11 @@
1571 pass1585 pass
15721586
15731587
1588_gcchk_factory = _LeafNode
1589
1574try:1590try:
1575 from bzrlib import _btree_serializer_pyx as _btree_serializer1591 from bzrlib import _btree_serializer_pyx as _btree_serializer
1592 _gcchk_factory = _btree_serializer._parse_into_chk
1576except ImportError, e:1593except ImportError, e:
1577 osutils.failed_to_load_extension(e)1594 osutils.failed_to_load_extension(e)
1578 from bzrlib import _btree_serializer_py as _btree_serializer1595 from bzrlib import _btree_serializer_py as _btree_serializer
15791596
=== modified file 'bzrlib/bugtracker.py'
--- bzrlib/bugtracker.py 2010-04-30 11:03:59 +0000
+++ bzrlib/bugtracker.py 2011-02-09 08:08:20 +0000
@@ -93,7 +93,7 @@
93--fixes`` to mark bugs in that tracker as being fixed by that commit. For93--fixes`` to mark bugs in that tracker as being fixed by that commit. For
94example::94example::
9595
96 bugzilla_squid_url = http://www.squid-cache.org/bugs96 bugzilla_squid_url = http://bugs.squid-cache.org
9797
98would allow ``bzr commit --fixes squid:1234`` to mark Squid's bug 1234 as98would allow ``bzr commit --fixes squid:1234`` to mark Squid's bug 1234 as
99fixed.99fixed.
@@ -127,7 +127,13 @@
127127
128 bugtracker_cpan_url = http://rt.cpan.org/Public/Bug/Display.html?id={id}128 bugtracker_cpan_url = http://rt.cpan.org/Public/Bug/Display.html?id={id}
129129
130for CPAN's RT bug tracker.130would allow ``bzr commit --fixes cpan:1234`` to mark bug 1234 in CPAN's
131RT bug tracker as fixed, or::
132
133 bugtracker_hudson_url = http://issues.hudson-ci.org/browse/{id}
134
135would allow ``bzr commit --fixes hudson:HUDSON-1234`` to mark bug HUDSON-1234
136in Hudson's JIRA bug tracker as fixed.
131"""137"""
132138
133139
@@ -228,14 +234,13 @@
228 UniqueIntegerBugTracker('gnome', 'http://bugzilla.gnome.org/show_bug.cgi?id='))234 UniqueIntegerBugTracker('gnome', 'http://bugzilla.gnome.org/show_bug.cgi?id='))
229235
230236
231class URLParametrizedIntegerBugTracker(IntegerBugTracker):237class URLParametrizedBugTracker(BugTracker):
232 """A type of bug tracker that can be found on a variety of different sites,238 """A type of bug tracker that can be found on a variety of different sites,
233 and thus needs to have the base URL configured.239 and thus needs to have the base URL configured.
234240
235 Looks for a config setting in the form '<type_name>_<abbreviation>_url'.241 Looks for a config setting in the form '<type_name>_<abbreviation>_url'.
236 `type_name` is the name of the type of tracker (e.g. 'bugzilla' or 'trac')242 `type_name` is the name of the type of tracker and `abbreviation`
237 and `abbreviation` is a short name for the particular instance (e.g.243 is a short name for the particular instance.
238 'squid' or 'apache').
239 """244 """
240245
241 def get(self, abbreviation, branch):246 def get(self, abbreviation, branch):
@@ -256,6 +261,16 @@
256 return urlutils.join(self._base_url, self._bug_area) + str(bug_id)261 return urlutils.join(self._base_url, self._bug_area) + str(bug_id)
257262
258263
264class URLParametrizedIntegerBugTracker(IntegerBugTracker, URLParametrizedBugTracker):
265 """A type of bug tracker that can be found on a variety of different sites,
266 and thus needs to have the base URL configured, but only allows integer bug IDs.
267
268 Looks for a config setting in the form '<type_name>_<abbreviation>_url'.
269 `type_name` is the name of the type of tracker (e.g. 'bugzilla' or 'trac')
270 and `abbreviation` is a short name for the particular instance (e.g.
271 'squid' or 'apache').
272 """
273
259tracker_registry.register(274tracker_registry.register(
260 'trac', URLParametrizedIntegerBugTracker('trac', 'ticket/'))275 'trac', URLParametrizedIntegerBugTracker('trac', 'ticket/'))
261276
@@ -264,7 +279,7 @@
264 URLParametrizedIntegerBugTracker('bugzilla', 'show_bug.cgi?id='))279 URLParametrizedIntegerBugTracker('bugzilla', 'show_bug.cgi?id='))
265280
266281
267class GenericBugTracker(URLParametrizedIntegerBugTracker):282class GenericBugTracker(URLParametrizedBugTracker):
268 """Generic bug tracker specified by an URL template."""283 """Generic bug tracker specified by an URL template."""
269284
270 def __init__(self):285 def __init__(self):
271286
=== modified file 'bzrlib/builtins.py'
--- bzrlib/builtins.py 2010-07-28 07:05:19 +0000
+++ bzrlib/builtins.py 2011-02-09 08:08:20 +0000
@@ -1,4 +1,4 @@
1# Copyright (C) 2005-2010 Canonical Ltd1# Copyright (C) 2005-2011 Canonical Ltd
2#2#
3# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -20,7 +20,6 @@
2020
21from bzrlib.lazy_import import lazy_import21from bzrlib.lazy_import import lazy_import
22lazy_import(globals(), """22lazy_import(globals(), """
23import codecs
24import cStringIO23import cStringIO
25import sys24import sys
26import time25import time
@@ -33,7 +32,7 @@
33 bzrdir,32 bzrdir,
34 directory_service,33 directory_service,
35 delta,34 delta,
36 config,35 config as _mod_config,
37 errors,36 errors,
38 globbing,37 globbing,
39 hooks,38 hooks,
@@ -75,14 +74,11 @@
75from bzrlib.trace import mutter, note, warning, is_quiet, get_verbosity_level74from bzrlib.trace import mutter, note, warning, is_quiet, get_verbosity_level
7675
7776
77@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
78def tree_files(file_list, default_branch=u'.', canonicalize=True,78def tree_files(file_list, default_branch=u'.', canonicalize=True,
79 apply_view=True):79 apply_view=True):
80 try:80 return internal_tree_files(file_list, default_branch, canonicalize,
81 return internal_tree_files(file_list, default_branch, canonicalize,81 apply_view)
82 apply_view)
83 except errors.FileInWrongBranch, e:
84 raise errors.BzrCommandError("%s is not in the same branch as %s" %
85 (e.path, file_list[0]))
8682
8783
88def tree_files_for_add(file_list):84def tree_files_for_add(file_list):
@@ -152,10 +148,13 @@
152148
153# XXX: Bad function name; should possibly also be a class method of149# XXX: Bad function name; should possibly also be a class method of
154# WorkingTree rather than a function.150# WorkingTree rather than a function.
151@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
155def internal_tree_files(file_list, default_branch=u'.', canonicalize=True,152def internal_tree_files(file_list, default_branch=u'.', canonicalize=True,
156 apply_view=True):153 apply_view=True):
157 """Convert command-line paths to a WorkingTree and relative paths.154 """Convert command-line paths to a WorkingTree and relative paths.
158155
156 Deprecated: use WorkingTree.open_containing_paths instead.
157
159 This is typically used for command-line processors that take one or158 This is typically used for command-line processors that take one or
160 more filenames, and infer the workingtree that contains them.159 more filenames, and infer the workingtree that contains them.
161160
@@ -171,53 +170,10 @@
171170
172 :return: workingtree, [relative_paths]171 :return: workingtree, [relative_paths]
173 """172 """
174 if file_list is None or len(file_list) == 0:173 return WorkingTree.open_containing_paths(
175 tree = WorkingTree.open_containing(default_branch)[0]174 file_list, default_directory='.',
176 if tree.supports_views() and apply_view:175 canonicalize=True,
177 view_files = tree.views.lookup_view()176 apply_view=True)
178 if view_files:
179 file_list = view_files
180 view_str = views.view_display_str(view_files)
181 note("Ignoring files outside view. View is %s" % view_str)
182 return tree, file_list
183 tree = WorkingTree.open_containing(file_list[0])[0]
184 return tree, safe_relpath_files(tree, file_list, canonicalize,
185 apply_view=apply_view)
186
187
188def safe_relpath_files(tree, file_list, canonicalize=True, apply_view=True):
189 """Convert file_list into a list of relpaths in tree.
190
191 :param tree: A tree to operate on.
192 :param file_list: A list of user provided paths or None.
193 :param apply_view: if True and a view is set, apply it or check that
194 specified files are within it
195 :return: A list of relative paths.
196 :raises errors.PathNotChild: When a provided path is in a different tree
197 than tree.
198 """
199 if file_list is None:
200 return None
201 if tree.supports_views() and apply_view:
202 view_files = tree.views.lookup_view()
203 else:
204 view_files = []
205 new_list = []
206 # tree.relpath exists as a "thunk" to osutils, but canonical_relpath
207 # doesn't - fix that up here before we enter the loop.
208 if canonicalize:
209 fixer = lambda p: osutils.canonical_relpath(tree.basedir, p)
210 else:
211 fixer = tree.relpath
212 for filename in file_list:
213 try:
214 relpath = fixer(osutils.dereference_path(filename))
215 if view_files and not osutils.is_inside_any(view_files, relpath):
216 raise errors.FileOutsideView(filename, view_files)
217 new_list.append(relpath)
218 except errors.PathNotChild:
219 raise errors.FileInWrongBranch(tree.branch, filename)
220 return new_list
221177
222178
223def _get_view_info_for_change_reporter(tree):179def _get_view_info_for_change_reporter(tree):
@@ -294,8 +250,12 @@
294 To skip the display of pending merge information altogether, use250 To skip the display of pending merge information altogether, use
295 the no-pending option or specify a file/directory.251 the no-pending option or specify a file/directory.
296252
297 If a revision argument is given, the status is calculated against253 To compare the working directory to a specific revision, pass a
298 that revision, or between two revisions if two are provided.254 single revision to the revision argument.
255
256 To see which files have changed in a specific revision, or between
257 two revisions, pass a revision range to the revision argument.
258 This will produce the same results as calling 'bzr diff --summarize'.
299 """259 """
300260
301 # TODO: --no-recurse, --recurse options261 # TODO: --no-recurse, --recurse options
@@ -323,7 +283,7 @@
323 raise errors.BzrCommandError('bzr status --revision takes exactly'283 raise errors.BzrCommandError('bzr status --revision takes exactly'
324 ' one or two revision specifiers')284 ' one or two revision specifiers')
325285
326 tree, relfile_list = tree_files(file_list)286 tree, relfile_list = WorkingTree.open_containing_paths(file_list)
327 # Avoid asking for specific files when that is not needed.287 # Avoid asking for specific files when that is not needed.
328 if relfile_list == ['']:288 if relfile_list == ['']:
329 relfile_list = None289 relfile_list = None
@@ -368,7 +328,8 @@
368 if revision_id is None and revision is None:328 if revision_id is None and revision is None:
369 raise errors.BzrCommandError('You must supply either'329 raise errors.BzrCommandError('You must supply either'
370 ' --revision or a revision_id')330 ' --revision or a revision_id')
371 b = WorkingTree.open_containing(directory)[0].branch331
332 b = bzrdir.BzrDir.open_containing_tree_or_branch(directory)[1]
372333
373 revisions = b.repository.revisions334 revisions = b.repository.revisions
374 if revisions is None:335 if revisions is None:
@@ -521,6 +482,59 @@
521 d.destroy_workingtree()482 d.destroy_workingtree()
522483
523484
485class cmd_repair_workingtree(Command):
486 __doc__ = """Reset the working tree state file.
487
488 This is not meant to be used normally, but more as a way to recover from
489 filesystem corruption, etc. This rebuilds the working inventory back to a
490 'known good' state. Any new modifications (adding a file, renaming, etc)
491 will be lost, though modified files will still be detected as such.
492
493 Most users will want something more like "bzr revert" or "bzr update"
494 unless the state file has become corrupted.
495
496 By default this attempts to recover the current state by looking at the
497 headers of the state file. If the state file is too corrupted to even do
498 that, you can supply --revision to force the state of the tree.
499 """
500
501 takes_options = ['revision', 'directory',
502 Option('force',
503 help='Reset the tree even if it doesn\'t appear to be'
504 ' corrupted.'),
505 ]
506 hidden = True
507
508 def run(self, revision=None, directory='.', force=False):
509 tree, _ = WorkingTree.open_containing(directory)
510 self.add_cleanup(tree.lock_tree_write().unlock)
511 if not force:
512 try:
513 tree.check_state()
514 except errors.BzrError:
515 pass # There seems to be a real error here, so we'll reset
516 else:
517 # Refuse
518 raise errors.BzrCommandError(
519 'The tree does not appear to be corrupt. You probably'
520 ' want "bzr revert" instead. Use "--force" if you are'
521 ' sure you want to reset the working tree.')
522 if revision is None:
523 revision_ids = None
524 else:
525 revision_ids = [r.as_revision_id(tree.branch) for r in revision]
526 try:
527 tree.reset_state(revision_ids)
528 except errors.BzrError, e:
529 if revision_ids is None:
530 extra = (', the header appears corrupt, try passing -r -1'
531 ' to set the state to the last commit')
532 else:
533 extra = ''
534 raise errors.BzrCommandError('failed to reset the tree state'
535 + extra)
536
537
524class cmd_revno(Command):538class cmd_revno(Command):
525 __doc__ = """Show current revision number.539 __doc__ = """Show current revision number.
526540
@@ -761,7 +775,7 @@
761 raise errors.BzrCommandError('invalid kind %r specified' % (kind,))775 raise errors.BzrCommandError('invalid kind %r specified' % (kind,))
762776
763 revision = _get_one_revision('inventory', revision)777 revision = _get_one_revision('inventory', revision)
764 work_tree, file_list = tree_files(file_list)778 work_tree, file_list = WorkingTree.open_containing_paths(file_list)
765 self.add_cleanup(work_tree.lock_read().unlock)779 self.add_cleanup(work_tree.lock_read().unlock)
766 if revision is not None:780 if revision is not None:
767 tree = revision.as_tree(work_tree.branch)781 tree = revision.as_tree(work_tree.branch)
@@ -832,7 +846,7 @@
832 names_list = []846 names_list = []
833 if len(names_list) < 2:847 if len(names_list) < 2:
834 raise errors.BzrCommandError("missing file argument")848 raise errors.BzrCommandError("missing file argument")
835 tree, rel_names = tree_files(names_list, canonicalize=False)849 tree, rel_names = WorkingTree.open_containing_paths(names_list, canonicalize=False)
836 self.add_cleanup(tree.lock_tree_write().unlock)850 self.add_cleanup(tree.lock_tree_write().unlock)
837 self._run(tree, names_list, rel_names, after)851 self._run(tree, names_list, rel_names, after)
838852
@@ -843,7 +857,8 @@
843 if after:857 if after:
844 raise errors.BzrCommandError('--after cannot be specified with'858 raise errors.BzrCommandError('--after cannot be specified with'
845 ' --auto.')859 ' --auto.')
846 work_tree, file_list = tree_files(names_list, default_branch='.')860 work_tree, file_list = WorkingTree.open_containing_paths(
861 names_list, default_directory='.')
847 self.add_cleanup(work_tree.lock_tree_write().unlock)862 self.add_cleanup(work_tree.lock_tree_write().unlock)
848 rename_map.RenameMap.guess_renames(work_tree, dry_run)863 rename_map.RenameMap.guess_renames(work_tree, dry_run)
849864
@@ -966,13 +981,16 @@
966 "branch. Local pulls are not applied to "981 "branch. Local pulls are not applied to "
967 "the master branch."982 "the master branch."
968 ),983 ),
984 Option('show-base',
985 help="Show base revision text in conflicts.")
969 ]986 ]
970 takes_args = ['location?']987 takes_args = ['location?']
971 encoding_type = 'replace'988 encoding_type = 'replace'
972989
973 def run(self, location=None, remember=False, overwrite=False,990 def run(self, location=None, remember=False, overwrite=False,
974 revision=None, verbose=False,991 revision=None, verbose=False,
975 directory=None, local=False):992 directory=None, local=False,
993 show_base=False):
976 # FIXME: too much stuff is in the command class994 # FIXME: too much stuff is in the command class
977 revision_id = None995 revision_id = None
978 mergeable = None996 mergeable = None
@@ -987,6 +1005,9 @@
987 branch_to = Branch.open_containing(directory)[0]1005 branch_to = Branch.open_containing(directory)[0]
988 self.add_cleanup(branch_to.lock_write().unlock)1006 self.add_cleanup(branch_to.lock_write().unlock)
9891007
1008 if tree_to is None and show_base:
1009 raise errors.BzrCommandError("Need working tree for --show-base.")
1010
990 if local and not branch_to.get_bound_location():1011 if local and not branch_to.get_bound_location():
991 raise errors.LocalRequiresBoundBranch()1012 raise errors.LocalRequiresBoundBranch()
9921013
@@ -1037,7 +1058,8 @@
1037 view_info=view_info)1058 view_info=view_info)
1038 result = tree_to.pull(1059 result = tree_to.pull(
1039 branch_from, overwrite, revision_id, change_reporter,1060 branch_from, overwrite, revision_id, change_reporter,
1040 possible_transports=possible_transports, local=local)1061 possible_transports=possible_transports, local=local,
1062 show_base=show_base)
1041 else:1063 else:
1042 result = branch_to.pull(1064 result = branch_to.pull(
1043 branch_from, overwrite, revision_id, local=local)1065 branch_from, overwrite, revision_id, local=local)
@@ -1047,6 +1069,10 @@
1047 log.show_branch_change(1069 log.show_branch_change(
1048 branch_to, self.outf, result.old_revno,1070 branch_to, self.outf, result.old_revno,
1049 result.old_revid)1071 result.old_revid)
1072 if getattr(result, 'tag_conflicts', None):
1073 return 1
1074 else:
1075 return 0
10501076
10511077
1052class cmd_push(Command):1078class cmd_push(Command):
@@ -1099,6 +1125,9 @@
1099 Option('strict',1125 Option('strict',
1100 help='Refuse to push if there are uncommitted changes in'1126 help='Refuse to push if there are uncommitted changes in'
1101 ' the working tree, --no-strict disables the check.'),1127 ' the working tree, --no-strict disables the check.'),
1128 Option('no-tree',
1129 help="Don't populate the working tree, even for protocols"
1130 " that support it."),
1102 ]1131 ]
1103 takes_args = ['location?']1132 takes_args = ['location?']
1104 encoding_type = 'replace'1133 encoding_type = 'replace'
@@ -1106,7 +1135,7 @@
1106 def run(self, location=None, remember=False, overwrite=False,1135 def run(self, location=None, remember=False, overwrite=False,
1107 create_prefix=False, verbose=False, revision=None,1136 create_prefix=False, verbose=False, revision=None,
1108 use_existing_dir=False, directory=None, stacked_on=None,1137 use_existing_dir=False, directory=None, stacked_on=None,
1109 stacked=False, strict=None):1138 stacked=False, strict=None, no_tree=False):
1110 from bzrlib.push import _show_push_branch1139 from bzrlib.push import _show_push_branch
11111140
1112 if directory is None:1141 if directory is None:
@@ -1158,7 +1187,7 @@
1158 _show_push_branch(br_from, revision_id, location, self.outf,1187 _show_push_branch(br_from, revision_id, location, self.outf,
1159 verbose=verbose, overwrite=overwrite, remember=remember,1188 verbose=verbose, overwrite=overwrite, remember=remember,
1160 stacked_on=stacked_on, create_prefix=create_prefix,1189 stacked_on=stacked_on, create_prefix=create_prefix,
1161 use_existing_dir=use_existing_dir)1190 use_existing_dir=use_existing_dir, no_tree=no_tree)
11621191
11631192
1164class cmd_branch(Command):1193class cmd_branch(Command):
@@ -1177,8 +1206,10 @@
11771206
1178 _see_also = ['checkout']1207 _see_also = ['checkout']
1179 takes_args = ['from_location', 'to_location?']1208 takes_args = ['from_location', 'to_location?']
1180 takes_options = ['revision', Option('hardlink',1209 takes_options = ['revision',
1181 help='Hard-link working tree files where possible.'),1210 Option('hardlink', help='Hard-link working tree files where possible.'),
1211 Option('files-from', type=str,
1212 help="Get file contents from this tree."),
1182 Option('no-tree',1213 Option('no-tree',
1183 help="Create a branch without a working-tree."),1214 help="Create a branch without a working-tree."),
1184 Option('switch',1215 Option('switch',
@@ -1202,11 +1233,19 @@
12021233
1203 def run(self, from_location, to_location=None, revision=None,1234 def run(self, from_location, to_location=None, revision=None,
1204 hardlink=False, stacked=False, standalone=False, no_tree=False,1235 hardlink=False, stacked=False, standalone=False, no_tree=False,
1205 use_existing_dir=False, switch=False, bind=False):1236 use_existing_dir=False, switch=False, bind=False,
1237 files_from=None):
1206 from bzrlib import switch as _mod_switch1238 from bzrlib import switch as _mod_switch
1207 from bzrlib.tag import _merge_tags_if_possible1239 from bzrlib.tag import _merge_tags_if_possible
1208 accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(1240 accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
1209 from_location)1241 from_location)
1242 if not (hardlink or files_from):
1243 # accelerator_tree is usually slower because you have to read N
1244 # files (no readahead, lots of seeks, etc), but allow the user to
1245 # explicitly request it
1246 accelerator_tree = None
1247 if files_from is not None and files_from != from_location:
1248 accelerator_tree = WorkingTree.open(files_from)
1210 revision = _get_one_revision('branch', revision)1249 revision = _get_one_revision('branch', revision)
1211 self.add_cleanup(br_from.lock_read().unlock)1250 self.add_cleanup(br_from.lock_read().unlock)
1212 if revision is not None:1251 if revision is not None:
@@ -1319,8 +1358,13 @@
1319 to_location = branch_location1358 to_location = branch_location
1320 accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(1359 accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(
1321 branch_location)1360 branch_location)
1361 if not (hardlink or files_from):
1362 # accelerator_tree is usually slower because you have to read N
1363 # files (no readahead, lots of seeks, etc), but allow the user to
1364 # explicitly request it
1365 accelerator_tree = None
1322 revision = _get_one_revision('checkout', revision)1366 revision = _get_one_revision('checkout', revision)
1323 if files_from is not None:1367 if files_from is not None and files_from != branch_location:
1324 accelerator_tree = WorkingTree.open(files_from)1368 accelerator_tree = WorkingTree.open(files_from)
1325 if revision is not None:1369 if revision is not None:
1326 revision_id = revision.as_revision_id(source)1370 revision_id = revision.as_revision_id(source)
@@ -1382,16 +1426,22 @@
1382 If you want to discard your local changes, you can just do a1426 If you want to discard your local changes, you can just do a
1383 'bzr revert' instead of 'bzr commit' after the update.1427 'bzr revert' instead of 'bzr commit' after the update.
13841428
1429 If you want to restore a file that has been removed locally, use
1430 'bzr revert' instead of 'bzr update'.
1431
1385 If the tree's branch is bound to a master branch, it will also update1432 If the tree's branch is bound to a master branch, it will also update
1386 the branch from the master.1433 the branch from the master.
1387 """1434 """
13881435
1389 _see_also = ['pull', 'working-trees', 'status-flags']1436 _see_also = ['pull', 'working-trees', 'status-flags']
1390 takes_args = ['dir?']1437 takes_args = ['dir?']
1391 takes_options = ['revision']1438 takes_options = ['revision',
1439 Option('show-base',
1440 help="Show base revision text in conflicts."),
1441 ]
1392 aliases = ['up']1442 aliases = ['up']
13931443
1394 def run(self, dir='.', revision=None):1444 def run(self, dir='.', revision=None, show_base=None):
1395 if revision is not None and len(revision) != 1:1445 if revision is not None and len(revision) != 1:
1396 raise errors.BzrCommandError(1446 raise errors.BzrCommandError(
1397 "bzr update --revision takes exactly one revision")1447 "bzr update --revision takes exactly one revision")
@@ -1437,7 +1487,8 @@
1437 change_reporter,1487 change_reporter,
1438 possible_transports=possible_transports,1488 possible_transports=possible_transports,
1439 revision=revision_id,1489 revision=revision_id,
1440 old_tip=old_tip)1490 old_tip=old_tip,
1491 show_base=show_base)
1441 except errors.NoSuchRevision, e:1492 except errors.NoSuchRevision, e:
1442 raise errors.BzrCommandError(1493 raise errors.BzrCommandError(
1443 "branch has no revision %s\n"1494 "branch has no revision %s\n"
@@ -1505,10 +1556,11 @@
1505class cmd_remove(Command):1556class cmd_remove(Command):
1506 __doc__ = """Remove files or directories.1557 __doc__ = """Remove files or directories.
15071558
1508 This makes bzr stop tracking changes to the specified files. bzr will delete1559 This makes Bazaar stop tracking changes to the specified files. Bazaar will
1509 them if they can easily be recovered using revert. If no options or1560 delete them if they can easily be recovered using revert otherwise they
1510 parameters are given bzr will scan for files that are being tracked by bzr1561 will be backed up (adding an extention of the form .~#~). If no options or
1511 but missing in your tree and stop tracking them for you.1562 parameters are given Bazaar will scan for files that are being tracked by
1563 Bazaar but missing in your tree and stop tracking them for you.
1512 """1564 """
1513 takes_args = ['file*']1565 takes_args = ['file*']
1514 takes_options = ['verbose',1566 takes_options = ['verbose',
@@ -1516,17 +1568,23 @@
1516 RegistryOption.from_kwargs('file-deletion-strategy',1568 RegistryOption.from_kwargs('file-deletion-strategy',
1517 'The file deletion mode to be used.',1569 'The file deletion mode to be used.',
1518 title='Deletion Strategy', value_switches=True, enum_switch=False,1570 title='Deletion Strategy', value_switches=True, enum_switch=False,
1519 safe='Only delete files if they can be'1571 safe='Backup changed files (default).',
1520 ' safely recovered (default).',
1521 keep='Delete from bzr but leave the working copy.',1572 keep='Delete from bzr but leave the working copy.',
1573 no_backup='Don\'t backup changed files.',
1522 force='Delete all the specified files, even if they can not be '1574 force='Delete all the specified files, even if they can not be '
1523 'recovered and even if they are non-empty directories.')]1575 'recovered and even if they are non-empty directories. '
1576 '(deprecated, use no-backup)')]
1524 aliases = ['rm', 'del']1577 aliases = ['rm', 'del']
1525 encoding_type = 'replace'1578 encoding_type = 'replace'
15261579
1527 def run(self, file_list, verbose=False, new=False,1580 def run(self, file_list, verbose=False, new=False,
1528 file_deletion_strategy='safe'):1581 file_deletion_strategy='safe'):
1529 tree, file_list = tree_files(file_list)1582 if file_deletion_strategy == 'force':
1583 note("(The --force option is deprecated, rather use --no-backup "
1584 "in future.)")
1585 file_deletion_strategy = 'no-backup'
1586
1587 tree, file_list = WorkingTree.open_containing_paths(file_list)
15301588
1531 if file_list is not None:1589 if file_list is not None:
1532 file_list = [f for f in file_list]1590 file_list = [f for f in file_list]
@@ -1552,7 +1610,7 @@
1552 file_deletion_strategy = 'keep'1610 file_deletion_strategy = 'keep'
1553 tree.remove(file_list, verbose=verbose, to_file=self.outf,1611 tree.remove(file_list, verbose=verbose, to_file=self.outf,
1554 keep_files=file_deletion_strategy=='keep',1612 keep_files=file_deletion_strategy=='keep',
1555 force=file_deletion_strategy=='force')1613 force=(file_deletion_strategy=='no-backup'))
15561614
15571615
1558class cmd_file_id(Command):1616class cmd_file_id(Command):
@@ -1620,11 +1678,17 @@
16201678
1621 _see_also = ['check']1679 _see_also = ['check']
1622 takes_args = ['branch?']1680 takes_args = ['branch?']
1681 takes_options = [
1682 Option('canonicalize-chks',
1683 help='Make sure CHKs are in canonical form (repairs '
1684 'bug 522637).',
1685 hidden=True),
1686 ]
16231687
1624 def run(self, branch="."):1688 def run(self, branch=".", canonicalize_chks=False):
1625 from bzrlib.reconcile import reconcile1689 from bzrlib.reconcile import reconcile
1626 dir = bzrdir.BzrDir.open(branch)1690 dir = bzrdir.BzrDir.open(branch)
1627 reconcile(dir)1691 reconcile(dir, canonicalize_chks=canonicalize_chks)
16281692
16291693
1630class cmd_revision_history(Command):1694class cmd_revision_history(Command):
@@ -1707,10 +1771,12 @@
1707 ),1771 ),
1708 Option('append-revisions-only',1772 Option('append-revisions-only',
1709 help='Never change revnos or the existing log.'1773 help='Never change revnos or the existing log.'
1710 ' Append revisions to it only.')1774 ' Append revisions to it only.'),
1775 Option('no-tree',
1776 'Create a branch without a working tree.')
1711 ]1777 ]
1712 def run(self, location=None, format=None, append_revisions_only=False,1778 def run(self, location=None, format=None, append_revisions_only=False,
1713 create_prefix=False):1779 create_prefix=False, no_tree=False):
1714 if format is None:1780 if format is None:
1715 format = bzrdir.format_registry.make_bzrdir('default')1781 format = bzrdir.format_registry.make_bzrdir('default')
1716 if location is None:1782 if location is None:
@@ -1739,8 +1805,13 @@
1739 except errors.NotBranchError:1805 except errors.NotBranchError:
1740 # really a NotBzrDir error...1806 # really a NotBzrDir error...
1741 create_branch = bzrdir.BzrDir.create_branch_convenience1807 create_branch = bzrdir.BzrDir.create_branch_convenience
1808 if no_tree:
1809 force_new_tree = False
1810 else:
1811 force_new_tree = None
1742 branch = create_branch(to_transport.base, format=format,1812 branch = create_branch(to_transport.base, format=format,
1743 possible_transports=[to_transport])1813 possible_transports=[to_transport],
1814 force_new_tree=force_new_tree)
1744 a_bzrdir = branch.bzrdir1815 a_bzrdir = branch.bzrdir
1745 else:1816 else:
1746 from bzrlib.transport.local import LocalTransport1817 from bzrlib.transport.local import LocalTransport
@@ -1750,7 +1821,8 @@
1750 raise errors.BranchExistsWithoutWorkingTree(location)1821 raise errors.BranchExistsWithoutWorkingTree(location)
1751 raise errors.AlreadyBranchError(location)1822 raise errors.AlreadyBranchError(location)
1752 branch = a_bzrdir.create_branch()1823 branch = a_bzrdir.create_branch()
1753 a_bzrdir.create_workingtree()1824 if not no_tree:
1825 a_bzrdir.create_workingtree()
1754 if append_revisions_only:1826 if append_revisions_only:
1755 try:1827 try:
1756 branch.set_append_revisions_only(True)1828 branch.set_append_revisions_only(True)
@@ -1850,6 +1922,13 @@
1850 "bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and1922 "bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1851 produces patches suitable for "patch -p1".1923 produces patches suitable for "patch -p1".
18521924
1925 Note that when using the -r argument with a range of revisions, the
1926 differences are computed between the two specified revisions. That
1927 is, the command does not show the changes introduced by the first
1928 revision in the range. This differs from the interpretation of
1929 revision ranges used by "bzr log" which includes the first revision
1930 in the range.
1931
1853 :Exit values:1932 :Exit values:
1854 1 - changed1933 1 - changed
1855 2 - unrepresentable changes1934 2 - unrepresentable changes
@@ -1873,7 +1952,11 @@
18731952
1874 bzr diff -r1..3 xxx1953 bzr diff -r1..3 xxx
18751954
1876 To see the changes introduced in revision X::1955 The changes introduced by revision 2 (equivalent to -r1..2)::
1956
1957 bzr diff -c2
1958
1959 To see the changes introduced by revision X::
1877 1960
1878 bzr diff -cX1961 bzr diff -cX
18791962
@@ -1883,9 +1966,10 @@
18831966
1884 bzr diff -r<chosen_parent>..X1967 bzr diff -r<chosen_parent>..X
18851968
1886 The changes introduced by revision 2 (equivalent to -r1..2)::1969 The changes between the current revision and the previous revision
1970 (equivalent to -c-1 and -r-2..-1)
18871971
1888 bzr diff -c21972 bzr diff -r-2..
18891973
1890 Show just the differences for file NEWS::1974 Show just the differences for file NEWS::
18911975
@@ -1906,6 +1990,10 @@
1906 Same as 'bzr diff' but prefix paths with old/ and new/::1990 Same as 'bzr diff' but prefix paths with old/ and new/::
19071991
1908 bzr diff --prefix old/:new/1992 bzr diff --prefix old/:new/
1993
1994 Show the differences using a custom diff program with options::
1995
1996 bzr diff --using /usr/bin/diff --diff-options -wu
1909 """1997 """
1910 _see_also = ['status']1998 _see_also = ['status']
1911 takes_args = ['file*']1999 takes_args = ['file*']
@@ -1931,9 +2019,10 @@
1931 type=unicode,2019 type=unicode,
1932 ),2020 ),
1933 RegistryOption('format',2021 RegistryOption('format',
2022 short_name='F',
1934 help='Diff format to use.',2023 help='Diff format to use.',
1935 lazy_registry=('bzrlib.diff', 'format_registry'),2024 lazy_registry=('bzrlib.diff', 'format_registry'),
1936 value_switches=False, title='Diff format'),2025 title='Diff format'),
1937 ]2026 ]
1938 aliases = ['di', 'dif']2027 aliases = ['di', 'dif']
1939 encoding_type = 'exact'2028 encoding_type = 'exact'
@@ -2020,7 +2109,9 @@
2020 @display_command2109 @display_command
2021 def run(self, null=False, directory=u'.'):2110 def run(self, null=False, directory=u'.'):
2022 tree = WorkingTree.open_containing(directory)[0]2111 tree = WorkingTree.open_containing(directory)[0]
2112 self.add_cleanup(tree.lock_read().unlock)
2023 td = tree.changes_from(tree.basis_tree())2113 td = tree.changes_from(tree.basis_tree())
2114 self.cleanup_now()
2024 for path, id, kind, text_modified, meta_modified in td.modified:2115 for path, id, kind, text_modified, meta_modified in td.modified:
2025 if null:2116 if null:
2026 self.outf.write(path + '\0')2117 self.outf.write(path + '\0')
@@ -2656,8 +2747,13 @@
2656 Patterns prefixed with '!!' act as regular ignore patterns, but have2747 Patterns prefixed with '!!' act as regular ignore patterns, but have
2657 precedence over the '!' exception patterns.2748 precedence over the '!' exception patterns.
26582749
2659 Note: ignore patterns containing shell wildcards must be quoted from2750 :Notes:
2660 the shell on Unix.2751
2752 * Ignore patterns containing shell wildcards must be quoted from
2753 the shell on Unix.
2754
2755 * Ignore patterns starting with "#" act as comments in the ignore file.
2756 To ignore patterns that begin with that character, use the "RE:" prefix.
26612757
2662 :Examples:2758 :Examples:
2663 Ignore the top level Makefile::2759 Ignore the top level Makefile::
@@ -2672,6 +2768,10 @@
26722768
2673 bzr ignore "!special.class"2769 bzr ignore "!special.class"
26742770
2771 Ignore files whose name begins with the "#" character::
2772
2773 bzr ignore "RE:^#"
2774
2675 Ignore .o files under the lib directory::2775 Ignore .o files under the lib directory::
26762776
2677 bzr ignore "lib/**/*.o"2777 bzr ignore "lib/**/*.o"
@@ -3117,7 +3217,7 @@
31173217
3118 properties = {}3218 properties = {}
31193219
3120 tree, selected_list = tree_files(selected_list)3220 tree, selected_list = WorkingTree.open_containing_paths(selected_list)
3121 if selected_list == ['']:3221 if selected_list == ['']:
3122 # workaround - commit of root of tree should be exactly the same3222 # workaround - commit of root of tree should be exactly the same
3123 # as just default commit in that tree, and succeed even though3223 # as just default commit in that tree, and succeed even though
@@ -3158,9 +3258,9 @@
3158 def get_message(commit_obj):3258 def get_message(commit_obj):
3159 """Callback to get commit message"""3259 """Callback to get commit message"""
3160 if file:3260 if file:
3161 f = codecs.open(file, 'rt', osutils.get_user_encoding())3261 f = open(file)
3162 try:3262 try:
3163 my_message = f.read()3263 my_message = f.read().decode(osutils.get_user_encoding())
3164 finally:3264 finally:
3165 f.close()3265 f.close()
3166 elif message is not None:3266 elif message is not None:
@@ -3197,7 +3297,7 @@
3197 reporter=None, verbose=verbose, revprops=properties,3297 reporter=None, verbose=verbose, revprops=properties,
3198 authors=author, timestamp=commit_stamp,3298 authors=author, timestamp=commit_stamp,
3199 timezone=offset,3299 timezone=offset,
3200 exclude=safe_relpath_files(tree, exclude))3300 exclude=tree.safe_relpath_files(exclude))
3201 except PointlessCommit:3301 except PointlessCommit:
3202 raise errors.BzrCommandError("No changes to commit."3302 raise errors.BzrCommandError("No changes to commit."
3203 " Use --unchanged to commit anyhow.")3303 " Use --unchanged to commit anyhow.")
@@ -3287,27 +3387,62 @@
32873387
32883388
3289class cmd_upgrade(Command):3389class cmd_upgrade(Command):
3290 __doc__ = """Upgrade branch storage to current format.3390 __doc__ = """Upgrade a repository, branch or working tree to a newer format.
32913391
3292 The check command or bzr developers may sometimes advise you to run3392 When the default format has changed after a major new release of
3293 this command. When the default format has changed you may also be warned3393 Bazaar, you may be informed during certain operations that you
3294 during other operations to upgrade.3394 should upgrade. Upgrading to a newer format may improve performance
3395 or make new features available. It may however limit interoperability
3396 with older repositories or with older versions of Bazaar.
3397
3398 If you wish to upgrade to a particular format rather than the
3399 current default, that can be specified using the --format option.
3400 As a consequence, you can use the upgrade command this way to
3401 "downgrade" to an earlier format, though some conversions are
3402 a one way process (e.g. changing from the 1.x default to the
3403 2.x default) so downgrading is not always possible.
3404
3405 A backup.bzr.~#~ directory is created at the start of the conversion
3406 process (where # is a number). By default, this is left there on
3407 completion. If the conversion fails, delete the new .bzr directory
3408 and rename this one back in its place. Use the --clean option to ask
3409 for the backup.bzr directory to be removed on successful conversion.
3410 Alternatively, you can delete it by hand if everything looks good
3411 afterwards.
3412
3413 If the location given is a shared repository, dependent branches
3414 are also converted provided the repository converts successfully.
3415 If the conversion of a branch fails, remaining branches are still
3416 tried.
3417
3418 For more information on upgrades, see the Bazaar Upgrade Guide,
3419 http://doc.bazaar.canonical.com/latest/en/upgrade-guide/.
3295 """3420 """
32963421
3297 _see_also = ['check']3422 _see_also = ['check', 'reconcile', 'formats']
3298 takes_args = ['url?']3423 takes_args = ['url?']
3299 takes_options = [3424 takes_options = [
3300 RegistryOption('format',3425 RegistryOption('format',
3301 help='Upgrade to a specific format. See "bzr help'3426 help='Upgrade to a specific format. See "bzr help'
3302 ' formats" for details.',3427 ' formats" for details.',
3303 lazy_registry=('bzrlib.bzrdir', 'format_registry'),3428 lazy_registry=('bzrlib.bzrdir', 'format_registry'),
3304 converter=lambda name: bzrdir.format_registry.make_bzrdir(name),3429 converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
3305 value_switches=True, title='Branch format'),3430 value_switches=True, title='Branch format'),
3306 ]3431 Option('clean',
3432 help='Remove the backup.bzr directory if successful.'),
3433 Option('dry-run',
3434 help="Show what would be done, but don't actually do anything."),
3435 ]
33073436
3308 def run(self, url='.', format=None):3437 def run(self, url='.', format=None, clean=False, dry_run=False):
3309 from bzrlib.upgrade import upgrade3438 from bzrlib.upgrade import upgrade
3310 upgrade(url, format)3439 exceptions = upgrade(url, format, clean_up=clean, dry_run=dry_run)
3440 if exceptions:
3441 if len(exceptions) == 1:
3442 # Compatibility with historical behavior
3443 raise exceptions[0]
3444 else:
3445 return 3
33113446
33123447
3313class cmd_whoami(Command):3448class cmd_whoami(Command):
@@ -3340,7 +3475,7 @@
3340 try:3475 try:
3341 c = Branch.open_containing(u'.')[0].get_config()3476 c = Branch.open_containing(u'.')[0].get_config()
3342 except errors.NotBranchError:3477 except errors.NotBranchError:
3343 c = config.GlobalConfig()3478 c = _mod_config.GlobalConfig()
3344 else:3479 else:
3345 c = Branch.open(directory).get_config()3480 c = Branch.open(directory).get_config()
3346 if email:3481 if email:
@@ -3349,9 +3484,13 @@
3349 self.outf.write(c.username() + '\n')3484 self.outf.write(c.username() + '\n')
3350 return3485 return
33513486
3487 if email:
3488 raise errors.BzrCommandError("--email can only be used to display existing "
3489 "identity")
3490
3352 # display a warning if an email address isn't included in the given name.3491 # display a warning if an email address isn't included in the given name.
3353 try:3492 try:
3354 config.extract_email_address(name)3493 _mod_config.extract_email_address(name)
3355 except errors.NoEmailInUsername, e:3494 except errors.NoEmailInUsername, e:
3356 warning('"%s" does not seem to contain an email address. '3495 warning('"%s" does not seem to contain an email address. '
3357 'This is allowed, but not recommended.', name)3496 'This is allowed, but not recommended.', name)
@@ -3363,7 +3502,7 @@
3363 else:3502 else:
3364 c = Branch.open(directory).get_config()3503 c = Branch.open(directory).get_config()
3365 else:3504 else:
3366 c = config.GlobalConfig()3505 c = _mod_config.GlobalConfig()
3367 c.set_user_option('email', name)3506 c.set_user_option('email', name)
33683507
33693508
@@ -3436,13 +3575,13 @@
3436 'bzr alias --remove expects an alias to remove.')3575 'bzr alias --remove expects an alias to remove.')
3437 # If alias is not found, print something like:3576 # If alias is not found, print something like:
3438 # unalias: foo: not found3577 # unalias: foo: not found
3439 c = config.GlobalConfig()3578 c = _mod_config.GlobalConfig()
3440 c.unset_alias(alias_name)3579 c.unset_alias(alias_name)
34413580
3442 @display_command3581 @display_command
3443 def print_aliases(self):3582 def print_aliases(self):
3444 """Print out the defined aliases in a similar format to bash."""3583 """Print out the defined aliases in a similar format to bash."""
3445 aliases = config.GlobalConfig().get_aliases()3584 aliases = _mod_config.GlobalConfig().get_aliases()
3446 for key, value in sorted(aliases.iteritems()):3585 for key, value in sorted(aliases.iteritems()):
3447 self.outf.write('bzr alias %s="%s"\n' % (key, value))3586 self.outf.write('bzr alias %s="%s"\n' % (key, value))
34483587
@@ -3458,7 +3597,7 @@
34583597
3459 def set_alias(self, alias_name, alias_command):3598 def set_alias(self, alias_name, alias_command):
3460 """Save the alias in the global config."""3599 """Save the alias in the global config."""
3461 c = config.GlobalConfig()3600 c = _mod_config.GlobalConfig()
3462 c.set_alias(alias_name, alias_command)3601 c.set_alias(alias_name, alias_command)
34633602
34643603
@@ -3499,6 +3638,9 @@
3499 If you set BZR_TEST_PDB=1 when running selftest, failing tests will drop3638 If you set BZR_TEST_PDB=1 when running selftest, failing tests will drop
3500 into a pdb postmortem session.3639 into a pdb postmortem session.
35013640
3641 The --coverage=DIRNAME global option produces a report with covered code
3642 indicated.
3643
3502 :Examples:3644 :Examples:
3503 Run only tests relating to 'ignore'::3645 Run only tests relating to 'ignore'::
35043646
@@ -3588,10 +3730,7 @@
3588 randomize=None, exclude=None, strict=False,3730 randomize=None, exclude=None, strict=False,
3589 load_list=None, debugflag=None, starting_with=None, subunit=False,3731 load_list=None, debugflag=None, starting_with=None, subunit=False,
3590 parallel=None, lsprof_tests=False):3732 parallel=None, lsprof_tests=False):
3591 from bzrlib.tests import selftest3733 from bzrlib import tests
3592
3593 # Make deprecation warnings visible, unless -Werror is set
3594 symbol_versioning.activate_deprecation_warnings(override=False)
35953734
3596 if testspecs_list is not None:3735 if testspecs_list is not None:
3597 pattern = '|'.join(testspecs_list)3736 pattern = '|'.join(testspecs_list)
@@ -3638,7 +3777,14 @@
3638 "starting_with": starting_with3777 "starting_with": starting_with
3639 }3778 }
3640 selftest_kwargs.update(self.additional_selftest_args)3779 selftest_kwargs.update(self.additional_selftest_args)
3641 result = selftest(**selftest_kwargs)3780
3781 # Make deprecation warnings visible, unless -Werror is set
3782 cleanup = symbol_versioning.activate_deprecation_warnings(
3783 override=False)
3784 try:
3785 result = tests.selftest(**selftest_kwargs)
3786 finally:
3787 cleanup()
3642 return int(not result)3788 return int(not result)
36433789
36443790
@@ -3701,16 +3847,20 @@
3701 with bzr send. If neither is specified, the default is the upstream branch3847 with bzr send. If neither is specified, the default is the upstream branch
3702 or the branch most recently merged using --remember.3848 or the branch most recently merged using --remember.
37033849
3704 When merging a branch, by default the tip will be merged. To pick a different3850 When merging from a branch, by default bzr will try to merge in all new
3705 revision, pass --revision. If you specify two values, the first will be used as3851 work from the other branch, automatically determining an appropriate base
3706 BASE and the second one as OTHER. Merging individual revisions, or a subset of3852 revision. If this fails, you may need to give an explicit base.
3707 available revisions, like this is commonly referred to as "cherrypicking".3853
37083854 To pick a different ending revision, pass "--revision OTHER". bzr will
3709 Revision numbers are always relative to the branch being merged.3855 try to merge in all new work up to and including revision OTHER.
37103856
3711 By default, bzr will try to merge in all new work from the other3857 If you specify two values, "--revision BASE..OTHER", only revisions BASE
3712 branch, automatically determining an appropriate base. If this3858 through OTHER, excluding BASE but including OTHER, will be merged. If this
3713 fails, you may need to give an explicit base.3859 causes some revisions to be skipped, i.e. if the destination branch does
3860 not already contain revision BASE, such a merge is commonly referred to as
3861 a "cherrypick".
3862
3863 Revision numbers are always relative to the source branch.
37143864
3715 Merge will do its best to combine the changes in two branches, but there3865 Merge will do its best to combine the changes in two branches, but there
3716 are some kinds of problems only a human can fix. When it encounters those,3866 are some kinds of problems only a human can fix. When it encounters those,
@@ -3740,7 +3890,7 @@
3740 you to apply each diff hunk and file change, similar to "shelve".3890 you to apply each diff hunk and file change, similar to "shelve".
37413891
3742 :Examples:3892 :Examples:
3743 To merge the latest revision from bzr.dev::3893 To merge all new revisions from bzr.dev::
37443894
3745 bzr merge ../bzr.dev3895 bzr merge ../bzr.dev
37463896
@@ -3980,7 +4130,9 @@
3980 if ((remember or tree.branch.get_submit_branch() is None) and4130 if ((remember or tree.branch.get_submit_branch() is None) and
3981 user_location is not None):4131 user_location is not None):
3982 tree.branch.set_submit_branch(other_branch.base)4132 tree.branch.set_submit_branch(other_branch.base)
3983 _merge_tags_if_possible(other_branch, tree.branch)4133 # Merge tags (but don't set them in the master branch yet, the user
4134 # might revert this merge). Commit will propagate them.
4135 _merge_tags_if_possible(other_branch, tree.branch, ignore_master=True)
3984 merger = _mod_merge.Merger.from_revision_ids(pb, tree,4136 merger = _mod_merge.Merger.from_revision_ids(pb, tree,
3985 other_revision_id, base_revision_id, other_branch, base_branch)4137 other_revision_id, base_revision_id, other_branch, base_branch)
3986 if other_path != '':4138 if other_path != '':
@@ -4087,7 +4239,7 @@
4087 from bzrlib.conflicts import restore4239 from bzrlib.conflicts import restore
4088 if merge_type is None:4240 if merge_type is None:
4089 merge_type = _mod_merge.Merge3Merger4241 merge_type = _mod_merge.Merge3Merger
4090 tree, file_list = tree_files(file_list)4242 tree, file_list = WorkingTree.open_containing_paths(file_list)
4091 self.add_cleanup(tree.lock_write().unlock)4243 self.add_cleanup(tree.lock_write().unlock)
4092 parents = tree.get_parent_ids()4244 parents = tree.get_parent_ids()
4093 if len(parents) != 2:4245 if len(parents) != 2:
@@ -4154,9 +4306,10 @@
4154 last committed revision is used.4306 last committed revision is used.
41554307
4156 To remove only some changes, without reverting to a prior version, use4308 To remove only some changes, without reverting to a prior version, use
4157 merge instead. For example, "merge . --revision -2..-3" will remove the4309 merge instead. For example, "merge . -r -2..-3" (don't forget the ".")
4158 changes introduced by -2, without affecting the changes introduced by -1.4310 will remove the changes introduced by the second last commit (-2), without
4159 Or to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.4311 affecting the changes introduced by the last commit (-1). To remove
4312 certain changes on a hunk-by-hunk basis, see the shelve command.
41604313
4161 By default, any files that have been manually changed will be backed up4314 By default, any files that have been manually changed will be backed up
4162 first. (Files changed only by merge are not backed up.) Backup files have4315 first. (Files changed only by merge are not backed up.) Backup files have
@@ -4192,7 +4345,7 @@
4192 target branches.4345 target branches.
4193 """4346 """
41944347
4195 _see_also = ['cat', 'export']4348 _see_also = ['cat', 'export', 'merge', 'shelve']
4196 takes_options = [4349 takes_options = [
4197 'revision',4350 'revision',
4198 Option('no-backup', "Do not save backups of reverted files."),4351 Option('no-backup', "Do not save backups of reverted files."),
@@ -4203,7 +4356,7 @@
42034356
4204 def run(self, revision=None, no_backup=False, file_list=None,4357 def run(self, revision=None, no_backup=False, file_list=None,
4205 forget_merges=None):4358 forget_merges=None):
4206 tree, file_list = tree_files(file_list)4359 tree, file_list = WorkingTree.open_containing_paths(file_list)
4207 self.add_cleanup(tree.lock_tree_write().unlock)4360 self.add_cleanup(tree.lock_tree_write().unlock)
4208 if forget_merges:4361 if forget_merges:
4209 tree.set_parent_ids(tree.get_parent_ids()[:1])4362 tree.set_parent_ids(tree.get_parent_ids()[:1])
@@ -4491,26 +4644,9 @@
44914644
4492 @display_command4645 @display_command
4493 def run(self, verbose=False):4646 def run(self, verbose=False):
4494 import bzrlib.plugin4647 from bzrlib import plugin
4495 from inspect import getdoc4648 self.outf.writelines(
4496 result = []4649 plugin.describe_plugins(show_paths=verbose))
4497 for name, plugin in bzrlib.plugin.plugins().items():
4498 version = plugin.__version__
4499 if version == 'unknown':
4500 version = ''
4501 name_ver = '%s %s' % (name, version)
4502 d = getdoc(plugin.module)
4503 if d:
4504 doc = d.split('\n')[0]
4505 else:
4506 doc = '(no description)'
4507 result.append((name_ver, doc, plugin.path()))
4508 for name_ver, doc, path in sorted(result):
4509 self.outf.write("%s\n" % name_ver)
4510 self.outf.write(" %s\n" % doc)
4511 if verbose:
4512 self.outf.write(" %s\n" % path)
4513 self.outf.write("\n")
45144650
45154651
4516class cmd_testament(Command):4652class cmd_testament(Command):
@@ -4812,8 +4948,11 @@
4812 self.outf.write('The above revision(s) will be removed.\n')4948 self.outf.write('The above revision(s) will be removed.\n')
48134949
4814 if not force:4950 if not force:
4815 if not ui.ui_factory.get_boolean('Are you sure'):4951 if not ui.ui_factory.confirm_action(
4816 self.outf.write('Canceled')4952 'Uncommit these revisions',
4953 'bzrlib.builtins.uncommit',
4954 {}):
4955 self.outf.write('Canceled\n')
4817 return 04956 return 0
48184957
4819 mutter('Uncommitting from {%s} to {%s}',4958 mutter('Uncommitting from {%s} to {%s}',
@@ -4825,7 +4964,10 @@
48254964
48264965
4827class cmd_break_lock(Command):4966class cmd_break_lock(Command):
4828 __doc__ = """Break a dead lock on a repository, branch or working directory.4967 __doc__ = """Break a dead lock.
4968
4969 This command breaks a lock on a repository, branch, working directory or
4970 config file.
48294971
4830 CAUTION: Locks should only be broken when you are sure that the process4972 CAUTION: Locks should only be broken when you are sure that the process
4831 holding the lock has been stopped.4973 holding the lock has been stopped.
@@ -4836,17 +4978,33 @@
4836 :Examples:4978 :Examples:
4837 bzr break-lock4979 bzr break-lock
4838 bzr break-lock bzr+ssh://example.com/bzr/foo4980 bzr break-lock bzr+ssh://example.com/bzr/foo
4981 bzr break-lock --conf ~/.bazaar
4839 """4982 """
4983
4840 takes_args = ['location?']4984 takes_args = ['location?']
4985 takes_options = [
4986 Option('config',
4987 help='LOCATION is the directory where the config lock is.'),
4988 Option('force',
4989 help='Do not ask for confirmation before breaking the lock.'),
4990 ]
48414991
4842 def run(self, location=None, show=False):4992 def run(self, location=None, config=False, force=False):
4843 if location is None:4993 if location is None:
4844 location = u'.'4994 location = u'.'
4845 control, relpath = bzrdir.BzrDir.open_containing(location)4995 if force:
4846 try:4996 ui.ui_factory = ui.ConfirmationUserInterfacePolicy(ui.ui_factory,
4847 control.break_lock()4997 None,
4848 except NotImplementedError:4998 {'bzrlib.lockdir.break': True})
4849 pass4999 if config:
5000 conf = _mod_config.LockableConfig(file_name=location)
5001 conf.break_lock()
5002 else:
5003 control, relpath = bzrdir.BzrDir.open_containing(location)
5004 try:
5005 control.break_lock()
5006 except NotImplementedError:
5007 pass
48505008
48515009
4852class cmd_wait_until_signalled(Command):5010class cmd_wait_until_signalled(Command):
@@ -4937,7 +5095,7 @@
4937 not part of it. (Such trees can be produced by "bzr split", but also by5095 not part of it. (Such trees can be produced by "bzr split", but also by
4938 running "bzr branch" with the target inside a tree.)5096 running "bzr branch" with the target inside a tree.)
49395097
4940 The result is a combined tree, with the subtree no longer an independant5098 The result is a combined tree, with the subtree no longer an independent
4941 part. This is marked as a merge of the subtree into the containing tree,5099 part. This is marked as a merge of the subtree into the containing tree,
4942 and all history is preserved.5100 and all history is preserved.
4943 """5101 """
@@ -5339,7 +5497,7 @@
5339 if tag_name is None:5497 if tag_name is None:
5340 raise errors.BzrCommandError("No tag specified to delete.")5498 raise errors.BzrCommandError("No tag specified to delete.")
5341 branch.tags.delete_tag(tag_name)5499 branch.tags.delete_tag(tag_name)
5342 self.outf.write('Deleted tag %s.\n' % tag_name)5500 note('Deleted tag %s.' % tag_name)
5343 else:5501 else:
5344 if revision:5502 if revision:
5345 if len(revision) != 1:5503 if len(revision) != 1:
@@ -5357,7 +5515,7 @@
5357 if (not force) and branch.tags.has_tag(tag_name):5515 if (not force) and branch.tags.has_tag(tag_name):
5358 raise errors.TagAlreadyExists(tag_name)5516 raise errors.TagAlreadyExists(tag_name)
5359 branch.tags.set_tag(tag_name, revision_id)5517 branch.tags.set_tag(tag_name, revision_id)
5360 self.outf.write('Created tag %s.\n' % tag_name)5518 note('Created tag %s.' % tag_name)
53615519
53625520
5363class cmd_tags(Command):5521class cmd_tags(Command):
@@ -5370,22 +5528,17 @@
5370 takes_options = [5528 takes_options = [
5371 custom_help('directory',5529 custom_help('directory',
5372 help='Branch whose tags should be displayed.'),5530 help='Branch whose tags should be displayed.'),
5373 RegistryOption.from_kwargs('sort',5531 RegistryOption('sort',
5374 'Sort tags by different criteria.', title='Sorting',5532 'Sort tags by different criteria.', title='Sorting',
5375 alpha='Sort tags lexicographically (default).',5533 lazy_registry=('bzrlib.tag', 'tag_sort_methods')
5376 time='Sort tags chronologically.',
5377 ),5534 ),
5378 'show-ids',5535 'show-ids',
5379 'revision',5536 'revision',
5380 ]5537 ]
53815538
5382 @display_command5539 @display_command
5383 def run(self,5540 def run(self, directory='.', sort=None, show_ids=False, revision=None):
5384 directory='.',5541 from bzrlib.tag import tag_sort_methods
5385 sort='alpha',
5386 show_ids=False,
5387 revision=None,
5388 ):
5389 branch, relpath = Branch.open_containing(directory)5542 branch, relpath = Branch.open_containing(directory)
53905543
5391 tags = branch.tags.get_tag_dict().items()5544 tags = branch.tags.get_tag_dict().items()
@@ -5400,19 +5553,9 @@
5400 # only show revisions between revid1 and revid2 (inclusive)5553 # only show revisions between revid1 and revid2 (inclusive)
5401 tags = [(tag, revid) for tag, revid in tags if5554 tags = [(tag, revid) for tag, revid in tags if
5402 graph.is_between(revid, revid1, revid2)]5555 graph.is_between(revid, revid1, revid2)]
5403 if sort == 'alpha':5556 if sort is None:
5404 tags.sort()5557 sort = tag_sort_methods.get()
5405 elif sort == 'time':5558 sort(branch, tags)
5406 timestamps = {}
5407 for tag, revid in tags:
5408 try:
5409 revobj = branch.repository.get_revision(revid)
5410 except errors.NoSuchRevision:
5411 timestamp = sys.maxint # place them at the end
5412 else:
5413 timestamp = revobj.timestamp
5414 timestamps[revid] = timestamp
5415 tags.sort(key=lambda x: timestamps[x[1]])
5416 if not show_ids:5559 if not show_ids:
5417 # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]5560 # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
5418 for index, (tag, revid) in enumerate(tags):5561 for index, (tag, revid) in enumerate(tags):
@@ -5705,7 +5848,8 @@
5705 name=None,5848 name=None,
5706 switch=None,5849 switch=None,
5707 ):5850 ):
5708 tree, file_list = tree_files(file_list, apply_view=False)5851 tree, file_list = WorkingTree.open_containing_paths(file_list,
5852 apply_view=False)
5709 current_view, view_dict = tree.views.get_view_info()5853 current_view, view_dict = tree.views.get_view_info()
5710 if name is None:5854 if name is None:
5711 name = current_view5855 name = current_view
@@ -5815,7 +5959,7 @@
5815 location = "."5959 location = "."
5816 branch = Branch.open_containing(location)[0]5960 branch = Branch.open_containing(location)[0]
5817 branch.bzrdir.destroy_branch()5961 branch.bzrdir.destroy_branch()
5818 5962
58195963
5820class cmd_shelve(Command):5964class cmd_shelve(Command):
5821 __doc__ = """Temporarily set aside some changes from the current tree.5965 __doc__ = """Temporarily set aside some changes from the current tree.
@@ -5840,6 +5984,18 @@
58405984
5841 You can put multiple items on the shelf, and by default, 'unshelve' will5985 You can put multiple items on the shelf, and by default, 'unshelve' will
5842 restore the most recently shelved changes.5986 restore the most recently shelved changes.
5987
5988 For complicated changes, it is possible to edit the changes in a separate
5989 editor program to decide what the file remaining in the working copy
5990 should look like. To do this, add the configuration option
5991
5992 change_editor = PROGRAM @new_path @old_path
5993
5994 where @new_path is replaced with the path of the new version of the
5995 file and @old_path is replaced with the path of the old version of
5996 the file. The PROGRAM should save the new file with the desired
5997 contents of the file in the working tree.
5998
5843 """5999 """
58446000
5845 takes_args = ['file*']6001 takes_args = ['file*']
@@ -5857,12 +6013,12 @@
5857 Option('destroy',6013 Option('destroy',
5858 help='Destroy removed changes instead of shelving them.'),6014 help='Destroy removed changes instead of shelving them.'),
5859 ]6015 ]
5860 _see_also = ['unshelve']6016 _see_also = ['unshelve', 'configuration']
58616017
5862 def run(self, revision=None, all=False, file_list=None, message=None,6018 def run(self, revision=None, all=False, file_list=None, message=None,
5863 writer=None, list=False, destroy=False, directory=u'.'):6019 writer=None, list=False, destroy=False, directory=None):
5864 if list:6020 if list:
5865 return self.run_for_list()6021 return self.run_for_list(directory=directory)
5866 from bzrlib.shelf_ui import Shelver6022 from bzrlib.shelf_ui import Shelver
5867 if writer is None:6023 if writer is None:
5868 writer = bzrlib.option.diff_writer_registry.get()6024 writer = bzrlib.option.diff_writer_registry.get()
@@ -5876,8 +6032,10 @@
5876 except errors.UserAbort:6032 except errors.UserAbort:
5877 return 06033 return 0
58786034
5879 def run_for_list(self):6035 def run_for_list(self, directory=None):
5880 tree = WorkingTree.open_containing('.')[0]6036 if directory is None:
6037 directory = u'.'
6038 tree = WorkingTree.open_containing(directory)[0]
5881 self.add_cleanup(tree.lock_read().unlock)6039 self.add_cleanup(tree.lock_read().unlock)
5882 manager = tree.get_shelf_manager()6040 manager = tree.get_shelf_manager()
5883 shelves = manager.active_shelves()6041 shelves = manager.active_shelves()
@@ -6012,10 +6170,12 @@
6012 # be only called once.6170 # be only called once.
6013 for (name, aliases, module_name) in [6171 for (name, aliases, module_name) in [
6014 ('cmd_bundle_info', [], 'bzrlib.bundle.commands'),6172 ('cmd_bundle_info', [], 'bzrlib.bundle.commands'),
6173 ('cmd_config', [], 'bzrlib.config'),
6015 ('cmd_dpush', [], 'bzrlib.foreign'),6174 ('cmd_dpush', [], 'bzrlib.foreign'),
6016 ('cmd_version_info', [], 'bzrlib.cmd_version_info'),6175 ('cmd_version_info', [], 'bzrlib.cmd_version_info'),
6017 ('cmd_resolve', ['resolved'], 'bzrlib.conflicts'),6176 ('cmd_resolve', ['resolved'], 'bzrlib.conflicts'),
6018 ('cmd_conflicts', [], 'bzrlib.conflicts'),6177 ('cmd_conflicts', [], 'bzrlib.conflicts'),
6019 ('cmd_sign_my_commits', [], 'bzrlib.sign_my_commits'),6178 ('cmd_sign_my_commits', [], 'bzrlib.sign_my_commits'),
6179 ('cmd_test_script', [], 'bzrlib.cmd_test_script'),
6020 ]:6180 ]:
6021 builtin_command_registry.register_lazy(name, aliases, module_name)6181 builtin_command_registry.register_lazy(name, aliases, module_name)
60226182
=== modified file 'bzrlib/bundle/__init__.py'
--- bzrlib/bundle/__init__.py 2010-02-17 17:11:16 +0000
+++ bzrlib/bundle/__init__.py 2011-02-09 08:08:20 +0000
@@ -16,35 +16,26 @@
1616
17from cStringIO import StringIO17from cStringIO import StringIO
1818
19from bzrlib.symbol_versioning import deprecated_function, deprecated_in
20from bzrlib.lazy_import import lazy_import19from bzrlib.lazy_import import lazy_import
21lazy_import(globals(), """20lazy_import(globals(), """
22from bzrlib import (21from bzrlib import (
23 errors,22 errors,
23 transport as _mod_transport,
24 urlutils,24 urlutils,
25 )25 )
26from bzrlib.bundle import serializer as _serializer26from bzrlib.bundle import serializer as _serializer
27from bzrlib.merge_directive import MergeDirective27from bzrlib.merge_directive import MergeDirective
28from bzrlib.transport import (
29 do_catching_redirections,
30 get_transport,
31 )
32""")28""")
33from bzrlib.trace import note29from bzrlib.trace import note
3430
3531
36@deprecated_function(deprecated_in((1, 12, 0)))
37def read_bundle_from_url(url):
38 return read_mergeable_from_url(url, _do_directive=False)
39
40
41def read_mergeable_from_url(url, _do_directive=True, possible_transports=None):32def read_mergeable_from_url(url, _do_directive=True, possible_transports=None):
42 """Read mergable object from a given URL.33 """Read mergable object from a given URL.
4334
44 :return: An object supporting get_target_revision. Raises NotABundle if35 :return: An object supporting get_target_revision. Raises NotABundle if
45 the target is not a mergeable type.36 the target is not a mergeable type.
46 """37 """
47 child_transport = get_transport(url,38 child_transport = _mod_transport.get_transport(url,
48 possible_transports=possible_transports)39 possible_transports=possible_transports)
49 transport = child_transport.clone('..')40 transport = child_transport.clone('..')
50 filename = transport.relpath(child_transport.base)41 filename = transport.relpath(child_transport.base)
@@ -63,11 +54,11 @@
63 exclude_trailing_slash=False)54 exclude_trailing_slash=False)
64 if not filename:55 if not filename:
65 raise errors.NotABundle('A directory cannot be a bundle')56 raise errors.NotABundle('A directory cannot be a bundle')
66 return get_transport(url)57 return _mod_transport.get_transport(url)
6758
68 try:59 try:
69 bytef, transport = do_catching_redirections(get_bundle, transport,60 bytef, transport = _mod_transport.do_catching_redirections(
70 redirected_transport)61 get_bundle, transport, redirected_transport)
71 except errors.TooManyRedirections:62 except errors.TooManyRedirections:
72 raise errors.NotABundle(transport.clone(filename).base)63 raise errors.NotABundle(transport.clone(filename).base)
73 except (errors.ConnectionReset, errors.ConnectionError), e:64 except (errors.ConnectionReset, errors.ConnectionError), e:
7465
=== modified file 'bzrlib/bundle/bundle_data.py'
--- bzrlib/bundle/bundle_data.py 2010-06-16 12:47:51 +0000
+++ bzrlib/bundle/bundle_data.py 2011-02-09 08:08:20 +0000
@@ -289,7 +289,7 @@
289 def _validate_revision(self, inventory, revision_id):289 def _validate_revision(self, inventory, revision_id):
290 """Make sure all revision entries match their checksum."""290 """Make sure all revision entries match their checksum."""
291291
292 # This is a mapping from each revision id to it's sha hash292 # This is a mapping from each revision id to its sha hash
293 rev_to_sha1 = {}293 rev_to_sha1 = {}
294294
295 rev = self.get_revision(revision_id)295 rev = self.get_revision(revision_id)
@@ -715,12 +715,11 @@
715 ie.symlink_target = self.get_symlink_target(file_id)715 ie.symlink_target = self.get_symlink_target(file_id)
716 ie.revision = revision_id716 ie.revision = revision_id
717717
718 if kind in ('directory', 'symlink'):718 if kind == 'file':
719 ie.text_size, ie.text_sha1 = None, None
720 else:
721 ie.text_size, ie.text_sha1 = self.get_size_and_sha1(file_id)719 ie.text_size, ie.text_sha1 = self.get_size_and_sha1(file_id)
722 if (ie.text_size is None) and (kind == 'file'):720 if ie.text_size is None:
723 raise BzrError('Got a text_size of None for file_id %r' % file_id)721 raise BzrError(
722 'Got a text_size of None for file_id %r' % file_id)
724 inv.add(ie)723 inv.add(ie)
725724
726 sorted_entries = self.sorted_path_id()725 sorted_entries = self.sorted_path_id()
727726
=== modified file 'bzrlib/bundle/serializer/__init__.py'
--- bzrlib/bundle/serializer/__init__.py 2009-03-23 14:59:43 +0000
+++ bzrlib/bundle/serializer/__init__.py 2011-02-09 08:08:20 +0000
@@ -1,4 +1,4 @@
1# Copyright (C) 2005, 2006 Canonical Ltd1# Copyright (C) 2005, 2006, 2007, 2009, 2010 Canonical Ltd
2#2#
3# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -21,7 +21,10 @@
21from StringIO import StringIO21from StringIO import StringIO
22import re22import re
2323
24import bzrlib.errors as errors24from bzrlib import (
25 errors,
26 pyutils,
27 )
25from bzrlib.diff import internal_diff28from bzrlib.diff import internal_diff
26from bzrlib.revision import NULL_REVISION29from bzrlib.revision import NULL_REVISION
27# For backwards-compatibility30# For backwards-compatibility
@@ -151,17 +154,6 @@
151 """154 """
152 raise NotImplementedError155 raise NotImplementedError
153156
154 def write(self, source, revision_ids, forced_bases, f):
155 """Write the bundle to the supplied file.
156
157 DEPRECATED: see write_bundle
158 :param source: A source for revision information
159 :param revision_ids: The list of revision ids to serialize
160 :param forced_bases: A dict of revision -> base that overrides default
161 :param f: The file to output to
162 """
163 raise NotImplementedError
164
165 def _write_bundle(self, repository, revision_id, base_revision_id, out):157 def _write_bundle(self, repository, revision_id, base_revision_id, out):
166 """Helper function for translating write_bundle to write"""158 """Helper function for translating write_bundle to write"""
167 forced_bases = {revision_id:base_revision_id}159 forced_bases = {revision_id:base_revision_id}
@@ -202,8 +194,7 @@
202 :param overwrite: Should this version override a default194 :param overwrite: Should this version override a default
203 """195 """
204 def _loader(version):196 def _loader(version):
205 mod = __import__(module, globals(), locals(), [classname])197 klass = pyutils.get_named_object(module, classname)
206 klass = getattr(mod, classname)
207 return klass(version)198 return klass(version)
208 register(version, _loader, overwrite=overwrite)199 register(version, _loader, overwrite=overwrite)
209200
210201
=== modified file 'bzrlib/bundle/serializer/v4.py'
--- bzrlib/bundle/serializer/v4.py 2009-08-04 14:08:32 +0000
+++ bzrlib/bundle/serializer/v4.py 2011-02-09 08:08:20 +0000
@@ -1,4 +1,4 @@
1# Copyright (C) 2007 Canonical Ltd1# Copyright (C) 2007-2010 Canonical Ltd
2#2#
3# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -30,11 +30,49 @@
30 serializer,30 serializer,
31 trace,31 trace,
32 ui,32 ui,
33 versionedfile as _mod_versionedfile,
33 )34 )
34from bzrlib.bundle import bundle_data, serializer as bundle_serializer35from bzrlib.bundle import bundle_data, serializer as bundle_serializer
35from bzrlib import bencode36from bzrlib import bencode
3637
3738
39class _MPDiffInventoryGenerator(_mod_versionedfile._MPDiffGenerator):
40 """Generate Inventory diffs serialized inventories."""
41
42 def __init__(self, repo, inventory_keys):
43 super(_MPDiffInventoryGenerator, self).__init__(repo.inventories,
44 inventory_keys)
45 self.repo = repo
46 self.sha1s = {}
47
48 def iter_diffs(self):
49 """Compute the diffs one at a time."""
50 # This is instead of compute_diffs() since we guarantee our ordering of
51 # inventories, we don't have to do any buffering
52 self._find_needed_keys()
53 # We actually use a slightly different ordering. We grab all of the
54 # parents first, and then grab the ordered requests.
55 needed_ids = [k[-1] for k in self.present_parents]
56 needed_ids.extend([k[-1] for k in self.ordered_keys])
57 inv_to_str = self.repo._serializer.write_inventory_to_string
58 for inv in self.repo.iter_inventories(needed_ids):
59 revision_id = inv.revision_id
60 key = (revision_id,)
61 if key in self.present_parents:
62 # Not a key we will transmit, which is a shame, since because
63 # of that bundles don't work with stacked branches
64 parent_ids = None
65 else:
66 parent_ids = [k[-1] for k in self.parent_map[key]]
67 as_bytes = inv_to_str(inv)
68 self._process_one_record(key, (as_bytes,))
69 if parent_ids is None:
70 continue
71 diff = self.diffs.pop(key)
72 sha1 = osutils.sha_string(as_bytes)
73 yield revision_id, parent_ids, sha1, diff
74
75
38class BundleWriter(object):76class BundleWriter(object):
39 """Writer for bundle-format files.77 """Writer for bundle-format files.
4078
@@ -348,48 +386,10 @@
348 the other side.386 the other side.
349 """387 """
350 inventory_key_order = [(r,) for r in revision_order]388 inventory_key_order = [(r,) for r in revision_order]
351 parent_map = self.repository.inventories.get_parent_map(389 generator = _MPDiffInventoryGenerator(self.repository,
352 inventory_key_order)390 inventory_key_order)
353 missing_keys = set(inventory_key_order).difference(parent_map)391 for revision_id, parent_ids, sha1, diff in generator.iter_diffs():
354 if missing_keys:
355 raise errors.RevisionNotPresent(list(missing_keys)[0],
356 self.repository.inventories)
357 inv_to_str = self.repository._serializer.write_inventory_to_string
358 # Make sure that we grab the parent texts first
359 just_parents = set()
360 map(just_parents.update, parent_map.itervalues())
361 just_parents.difference_update(parent_map)
362 # Ignore ghost parents
363 present_parents = self.repository.inventories.get_parent_map(
364 just_parents)
365 ghost_keys = just_parents.difference(present_parents)
366 needed_inventories = list(present_parents) + inventory_key_order
367 needed_inventories = [k[-1] for k in needed_inventories]
368 all_lines = {}
369 for inv in self.repository.iter_inventories(needed_inventories):
370 revision_id = inv.revision_id
371 key = (revision_id,)
372 as_bytes = inv_to_str(inv)
373 # The sha1 is validated as the xml/textual form, not as the
374 # form-in-the-repository
375 sha1 = osutils.sha_string(as_bytes)
376 as_lines = osutils.split_lines(as_bytes)
377 del as_bytes
378 all_lines[key] = as_lines
379 if key in just_parents:
380 # We don't transmit those entries
381 continue
382 # Create an mpdiff for this text, and add it to the output
383 parent_keys = parent_map[key]
384 # See the comment in VF.make_mpdiffs about how this effects
385 # ordering when there are ghosts present. I think we have a latent
386 # bug
387 parent_lines = [all_lines[p_key] for p_key in parent_keys
388 if p_key not in ghost_keys]
389 diff = multiparent.MultiParent.from_lines(
390 as_lines, parent_lines)
391 text = ''.join(diff.to_patch())392 text = ''.join(diff.to_patch())
392 parent_ids = [k[-1] for k in parent_keys]
393 self.bundle.add_multiparent_record(text, sha1, parent_ids,393 self.bundle.add_multiparent_record(text, sha1, parent_ids,
394 'inventory', revision_id, None)394 'inventory', revision_id, None)
395395
396396
=== modified file 'bzrlib/bzrdir.py'
--- bzrlib/bzrdir.py 2010-11-26 18:13:30 +0000
+++ bzrlib/bzrdir.py 2011-02-09 08:08:20 +0000
@@ -1,4 +1,4 @@
1# Copyright (C) 2006-2010 Canonical Ltd1# Copyright (C) 2006-2011 Canonical Ltd
2#2#
3# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -34,20 +34,22 @@
34from bzrlib.lazy_import import lazy_import34from bzrlib.lazy_import import lazy_import
35lazy_import(globals(), """35lazy_import(globals(), """
36from stat import S_ISDIR36from stat import S_ISDIR
37import textwrap
3837
39import bzrlib38import bzrlib
40from bzrlib import (39from bzrlib import (
41 branch,40 branch,
42 config,41 config,
42 controldir,
43 errors,43 errors,
44 graph,44 graph,
45 lockable_files,45 lockable_files,
46 lockdir,46 lockdir,
47 osutils,47 osutils,
48 pyutils,
48 remote,49 remote,
49 repository,50 repository,
50 revision as _mod_revision,51 revision as _mod_revision,
52 transport as _mod_transport,
51 ui,53 ui,
52 urlutils,54 urlutils,
53 versionedfile,55 versionedfile,
@@ -65,14 +67,16 @@
65 )67 )
66from bzrlib.repofmt import pack_repo68from bzrlib.repofmt import pack_repo
67from bzrlib.smart.client import _SmartClient69from bzrlib.smart.client import _SmartClient
68from bzrlib.store.versioned import WeaveStore70from bzrlib.store.versioned import VersionedFileStore
69from bzrlib.transactions import WriteTransaction71from bzrlib.transactions import WriteTransaction
70from bzrlib.transport import (72from bzrlib.transport import (
71 do_catching_redirections,73 do_catching_redirections,
72 get_transport,
73 local,74 local,
74 )75 )
75from bzrlib.weave import Weave76from bzrlib.weave import (
77 WeaveFile,
78 Weave,
79 )
76""")80""")
7781
78from bzrlib.trace import (82from bzrlib.trace import (
@@ -86,42 +90,13 @@
86 registry,90 registry,
87 symbol_versioning,91 symbol_versioning,
88 )92 )
89 93from bzrlib.symbol_versioning import (
90 94 deprecated_in,
91class ControlComponent(object):95 deprecated_method,
92 """Abstract base class for control directory components.96 )
93 97
94 This provides interfaces that are common across bzrdirs, 98
95 repositories, branches, and workingtree control directories.99class BzrDir(controldir.ControlDir):
96
97 They all expose two urls and transports: the *user* URL is the
98 one that stops above the control directory (eg .bzr) and that
99 should normally be used in messages, and the *control* URL is
100 under that in eg .bzr/checkout and is used to read the control
101 files.
102
103 This can be used as a mixin and is intended to fit with
104 foreign formats.
105 """
106
107 @property
108 def control_transport(self):
109 raise NotImplementedError
110
111 @property
112 def control_url(self):
113 return self.control_transport.base
114
115 @property
116 def user_transport(self):
117 raise NotImplementedError
118
119 @property
120 def user_url(self):
121 return self.user_transport.base
122
123
124class BzrDir(ControlComponent):
125 """A .bzr control diretory.100 """A .bzr control diretory.
126101
127 BzrDir instances let you create or open any of the things that can be102 BzrDir instances let you create or open any of the things that can be
@@ -158,10 +133,6 @@
158 return133 return
159 thing_to_unlock.break_lock()134 thing_to_unlock.break_lock()
160135
161 def can_convert_format(self):
162 """Return true if this bzrdir is one whose format we can convert from."""
163 return True
164
165 def check_conversion_target(self, target_format):136 def check_conversion_target(self, target_format):
166 """Check that a bzrdir as a whole can be converted to a new format."""137 """Check that a bzrdir as a whole can be converted to a new format."""
167 # The only current restriction is that the repository content can be 138 # The only current restriction is that the repository content can be
@@ -202,28 +173,9 @@
202 format.get_format_description(),173 format.get_format_description(),
203 basedir)174 basedir)
204175
205 def clone(self, url, revision_id=None, force_new_repo=False,
206 preserve_stacking=False):
207 """Clone this bzrdir and its contents to url verbatim.
208
209 :param url: The url create the clone at. If url's last component does
210 not exist, it will be created.
211 :param revision_id: The tip revision-id to use for any branch or
212 working tree. If not None, then the clone operation may tune
213 itself to download less data.
214 :param force_new_repo: Do not use a shared repository for the target
215 even if one is available.
216 :param preserve_stacking: When cloning a stacked branch, stack the
217 new branch on top of the other branch's stacked-on branch.
218 """
219 return self.clone_on_transport(get_transport(url),
220 revision_id=revision_id,
221 force_new_repo=force_new_repo,
222 preserve_stacking=preserve_stacking)
223
224 def clone_on_transport(self, transport, revision_id=None,176 def clone_on_transport(self, transport, revision_id=None,
225 force_new_repo=False, preserve_stacking=False, stacked_on=None,177 force_new_repo=False, preserve_stacking=False, stacked_on=None,
226 create_prefix=False, use_existing_dir=True):178 create_prefix=False, use_existing_dir=True, no_tree=False):
227 """Clone this bzrdir and its contents to transport verbatim.179 """Clone this bzrdir and its contents to transport verbatim.
228180
229 :param transport: The transport for the location to produce the clone181 :param transport: The transport for the location to produce the clone
@@ -241,12 +193,12 @@
241 """193 """
242 # Overview: put together a broad description of what we want to end up194 # Overview: put together a broad description of what we want to end up
243 # with; then make as few api calls as possible to do it.195 # with; then make as few api calls as possible to do it.
244 196
245 # We may want to create a repo/branch/tree, if we do so what format197 # We may want to create a repo/branch/tree, if we do so what format
246 # would we want for each:198 # would we want for each:
247 require_stacking = (stacked_on is not None)199 require_stacking = (stacked_on is not None)
248 format = self.cloning_metadir(require_stacking)200 format = self.cloning_metadir(require_stacking)
249 201
250 # Figure out what objects we want:202 # Figure out what objects we want:
251 try:203 try:
252 local_repo = self.find_repository()204 local_repo = self.find_repository()
@@ -271,7 +223,7 @@
271 # we should look up the policy needs first, or just use it as a hint,223 # we should look up the policy needs first, or just use it as a hint,
272 # or something.224 # or something.
273 if local_repo:225 if local_repo:
274 make_working_trees = local_repo.make_working_trees()226 make_working_trees = local_repo.make_working_trees() and not no_tree
275 want_shared = local_repo.is_shared()227 want_shared = local_repo.is_shared()
276 repo_format_name = format.repository_format.network_name()228 repo_format_name = format.repository_format.network_name()
277 else:229 else:
@@ -326,26 +278,8 @@
326 # TODO: This should be given a Transport, and should chdir up; otherwise278 # TODO: This should be given a Transport, and should chdir up; otherwise
327 # this will open a new connection.279 # this will open a new connection.
328 def _make_tail(self, url):280 def _make_tail(self, url):
329 t = get_transport(url)281 t = _mod_transport.get_transport(url)
330 t.ensure_base()282 t.ensure_base()
331
332 @classmethod
333 def create(cls, base, format=None, possible_transports=None):
334 """Create a new BzrDir at the url 'base'.
335
336 :param format: If supplied, the format of branch to create. If not
337 supplied, the default is used.
338 :param possible_transports: If supplied, a list of transports that
339 can be reused to share a remote connection.
340 """
341 if cls is not BzrDir:
342 raise AssertionError("BzrDir.create always creates the default"
343 " format, not one of %r" % cls)
344 t = get_transport(base, possible_transports)
345 t.ensure_base()
346 if format is None:
347 format = BzrDirFormat.get_default_format()
348 return format.initialize_on_transport(t)
349283
350 @staticmethod284 @staticmethod
351 def find_bzrdirs(transport, evaluate=None, list_current=None):285 def find_bzrdirs(transport, evaluate=None, list_current=None):
@@ -388,15 +322,6 @@
388 for subdir in sorted(subdirs, reverse=True):322 for subdir in sorted(subdirs, reverse=True):
389 pending.append(current_transport.clone(subdir))323 pending.append(current_transport.clone(subdir))
390324
391 def list_branches(self):
392 """Return a sequence of all branches local to this control directory.
393
394 """
395 try:
396 return [self.open_branch()]
397 except (errors.NotBranchError, errors.NoRepositoryPresent):
398 return []
399
400 @staticmethod325 @staticmethod
401 def find_branches(transport):326 def find_branches(transport):
402 """Find all branches under a transport.327 """Find all branches under a transport.
@@ -425,29 +350,6 @@
425 ret.extend(branches)350 ret.extend(branches)
426 return ret351 return ret
427352
428 def destroy_repository(self):
429 """Destroy the repository in this BzrDir"""
430 raise NotImplementedError(self.destroy_repository)
431
432 def create_branch(self, name=None):
433 """Create a branch in this BzrDir.
434
435 :param name: Name of the colocated branch to create, None for
436 the default branch.
437
438 The bzrdir's format will control what branch format is created.
439 For more control see BranchFormatXX.create(a_bzrdir).
440 """
441 raise NotImplementedError(self.create_branch)
442
443 def destroy_branch(self, name=None):
444 """Destroy a branch in this BzrDir.
445
446 :param name: Name of the branch to destroy, None for the default
447 branch.
448 """
449 raise NotImplementedError(self.destroy_branch)
450
451 @staticmethod353 @staticmethod
452 def create_branch_and_repo(base, force_new_repo=False, format=None):354 def create_branch_and_repo(base, force_new_repo=False, format=None):
453 """Create a new BzrDir, Branch and Repository at the url 'base'.355 """Create a new BzrDir, Branch and Repository at the url 'base'.
@@ -566,7 +468,7 @@
566 """468 """
567 if force_new_tree:469 if force_new_tree:
568 # check for non local urls470 # check for non local urls
569 t = get_transport(base, possible_transports)471 t = _mod_transport.get_transport(base, possible_transports)
570 if not isinstance(t, local.LocalTransport):472 if not isinstance(t, local.LocalTransport):
571 raise errors.NotLocalUrl(base)473 raise errors.NotLocalUrl(base)
572 bzrdir = BzrDir.create(base, format, possible_transports)474 bzrdir = BzrDir.create(base, format, possible_transports)
@@ -594,7 +496,7 @@
594 :param format: Override for the bzrdir format to create.496 :param format: Override for the bzrdir format to create.
595 :return: The WorkingTree object.497 :return: The WorkingTree object.
596 """498 """
597 t = get_transport(base)499 t = _mod_transport.get_transport(base)
598 if not isinstance(t, local.LocalTransport):500 if not isinstance(t, local.LocalTransport):
599 raise errors.NotLocalUrl(base)501 raise errors.NotLocalUrl(base)
600 bzrdir = BzrDir.create_branch_and_repo(base,502 bzrdir = BzrDir.create_branch_and_repo(base,
@@ -602,42 +504,30 @@
602 format=format).bzrdir504 format=format).bzrdir
603 return bzrdir.create_workingtree()505 return bzrdir.create_workingtree()
604506
605 def create_workingtree(self, revision_id=None, from_branch=None,507 @deprecated_method(deprecated_in((2, 3, 0)))
606 accelerator_tree=None, hardlink=False):508 def generate_backup_name(self, base):
607 """Create a working tree at this BzrDir.509 return self._available_backup_name(base)
608510
609 :param revision_id: create it as of this revision id.511 def _available_backup_name(self, base):
610 :param from_branch: override bzrdir branch (for lightweight checkouts)512 """Find a non-existing backup file name based on base.
611 :param accelerator_tree: A tree which can be used for retrieving file513
612 contents more quickly than the revision tree, i.e. a workingtree.514 See bzrlib.osutils.available_backup_name about race conditions.
613 The revision tree will be used for cases where accelerator_tree's
614 content is different.
615 """515 """
616 raise NotImplementedError(self.create_workingtree)516 return osutils.available_backup_name(base, self.root_transport.has)
617517
618 def backup_bzrdir(self):518 def backup_bzrdir(self):
619 """Backup this bzr control directory.519 """Backup this bzr control directory.
620520
621 :return: Tuple with old path name and new path name521 :return: Tuple with old path name and new path name
622 """522 """
623 def name_gen(base='backup.bzr'):
624 counter = 1
625 name = "%s.~%d~" % (base, counter)
626 while self.root_transport.has(name):
627 counter += 1
628 name = "%s.~%d~" % (base, counter)
629 return name
630523
631 backup_dir=name_gen()
632 pb = ui.ui_factory.nested_progress_bar()524 pb = ui.ui_factory.nested_progress_bar()
633 try:525 try:
634 # FIXME: bug 300001 -- the backup fails if the backup directory
635 # already exists, but it should instead either remove it or make
636 # a new backup directory.
637 #
638 old_path = self.root_transport.abspath('.bzr')526 old_path = self.root_transport.abspath('.bzr')
527 backup_dir = self._available_backup_name('backup.bzr')
639 new_path = self.root_transport.abspath(backup_dir)528 new_path = self.root_transport.abspath(backup_dir)
640 ui.ui_factory.note('making backup of %s\n to %s' % (old_path, new_path,))529 ui.ui_factory.note('making backup of %s\n to %s'
530 % (old_path, new_path,))
641 self.root_transport.copy_tree('.bzr', backup_dir)531 self.root_transport.copy_tree('.bzr', backup_dir)
642 return (old_path, new_path)532 return (old_path, new_path)
643 finally:533 finally:
@@ -668,21 +558,6 @@
668 else:558 else:
669 pass559 pass
670560
671 def destroy_workingtree(self):
672 """Destroy the working tree at this BzrDir.
673
674 Formats that do not support this may raise UnsupportedOperation.
675 """
676 raise NotImplementedError(self.destroy_workingtree)
677
678 def destroy_workingtree_metadata(self):
679 """Destroy the control files for the working tree at this BzrDir.
680
681 The contents of working tree files are not affected.
682 Formats that do not support this may raise UnsupportedOperation.
683 """
684 raise NotImplementedError(self.destroy_workingtree_metadata)
685
686 def _find_containing(self, evaluate):561 def _find_containing(self, evaluate):
687 """Find something in a containing control directory.562 """Find something in a containing control directory.
688563
@@ -737,33 +612,6 @@
737 raise errors.NoRepositoryPresent(self)612 raise errors.NoRepositoryPresent(self)
738 return found_repo613 return found_repo
739614
740 def get_branch_reference(self, name=None):
741 """Return the referenced URL for the branch in this bzrdir.
742
743 :param name: Optional colocated branch name
744 :raises NotBranchError: If there is no Branch.
745 :raises NoColocatedBranchSupport: If a branch name was specified
746 but colocated branches are not supported.
747 :return: The URL the branch in this bzrdir references if it is a
748 reference branch, or None for regular branches.
749 """
750 if name is not None:
751 raise errors.NoColocatedBranchSupport(self)
752 return None
753
754 def get_branch_transport(self, branch_format, name=None):
755 """Get the transport for use by branch format in this BzrDir.
756
757 Note that bzr dirs that do not support format strings will raise
758 IncompatibleFormat if the branch format they are given has
759 a format string, and vice versa.
760
761 If branch_format is None, the transport is returned with no
762 checking. If it is not None, then the returned transport is
763 guaranteed to point to an existing directory ready for use.
764 """
765 raise NotImplementedError(self.get_branch_transport)
766
767 def _find_creation_modes(self):615 def _find_creation_modes(self):
768 """Determine the appropriate modes for files and directories.616 """Determine the appropriate modes for files and directories.
769617
@@ -808,32 +656,6 @@
808 self._find_creation_modes()656 self._find_creation_modes()
809 return self._dir_mode657 return self._dir_mode
810658
811 def get_repository_transport(self, repository_format):
812 """Get the transport for use by repository format in this BzrDir.
813
814 Note that bzr dirs that do not support format strings will raise
815 IncompatibleFormat if the repository format they are given has
816 a format string, and vice versa.
817
818 If repository_format is None, the transport is returned with no
819 checking. If it is not None, then the returned transport is
820 guaranteed to point to an existing directory ready for use.
821 """
822 raise NotImplementedError(self.get_repository_transport)
823
824 def get_workingtree_transport(self, tree_format):
825 """Get the transport for use by workingtree format in this BzrDir.
826
827 Note that bzr dirs that do not support format strings will raise
828 IncompatibleFormat if the workingtree format they are given has a
829 format string, and vice versa.
830
831 If workingtree_format is None, the transport is returned with no
832 checking. If it is not None, then the returned transport is
833 guaranteed to point to an existing directory ready for use.
834 """
835 raise NotImplementedError(self.get_workingtree_transport)
836
837 def get_config(self):659 def get_config(self):
838 """Get configuration for this BzrDir."""660 """Get configuration for this BzrDir."""
839 return config.BzrDirConfig(self)661 return config.BzrDirConfig(self)
@@ -857,11 +679,11 @@
857 self.transport = _transport.clone('.bzr')679 self.transport = _transport.clone('.bzr')
858 self.root_transport = _transport680 self.root_transport = _transport
859 self._mode_check_done = False681 self._mode_check_done = False
860 682
861 @property 683 @property
862 def user_transport(self):684 def user_transport(self):
863 return self.root_transport685 return self.root_transport
864 686
865 @property687 @property
866 def control_transport(self):688 def control_transport(self):
867 return self.transport689 return self.transport
@@ -873,9 +695,7 @@
873695
874 This is true IF and ONLY IF the filename is part of the namespace reserved696 This is true IF and ONLY IF the filename is part of the namespace reserved
875 for bzr control dirs. Currently this is the '.bzr' directory in the root697 for bzr control dirs. Currently this is the '.bzr' directory in the root
876 of the root_transport. it is expected that plugins will need to extend698 of the root_transport.
877 this in the future - for instance to make bzr talk with svn working
878 trees.
879 """699 """
880 # this might be better on the BzrDirFormat class because it refers to700 # this might be better on the BzrDirFormat class because it refers to
881 # all the possible bzrdir disk formats.701 # all the possible bzrdir disk formats.
@@ -885,17 +705,6 @@
885 # add new tests for it to the appropriate place.705 # add new tests for it to the appropriate place.
886 return filename == '.bzr' or filename.startswith('.bzr/')706 return filename == '.bzr' or filename.startswith('.bzr/')
887707
888 def needs_format_conversion(self, format=None):
889 """Return true if this bzrdir needs convert_format run on it.
890
891 For instance, if the repository format is out of date but the
892 branch and working tree are not, this should return True.
893
894 :param format: Optional parameter indicating a specific desired
895 format we plan to arrive at.
896 """
897 raise NotImplementedError(self.needs_format_conversion)
898
899 @staticmethod708 @staticmethod
900 def open_unsupported(base):709 def open_unsupported(base):
901 """Open a branch which is not supported."""710 """Open a branch which is not supported."""
@@ -907,7 +716,7 @@
907716
908 :param _unsupported: a private parameter to the BzrDir class.717 :param _unsupported: a private parameter to the BzrDir class.
909 """718 """
910 t = get_transport(base, possible_transports=possible_transports)719 t = _mod_transport.get_transport(base, possible_transports)
911 return BzrDir.open_from_transport(t, _unsupported=_unsupported)720 return BzrDir.open_from_transport(t, _unsupported=_unsupported)
912721
913 @staticmethod722 @staticmethod
@@ -924,7 +733,7 @@
924 # the redirections.733 # the redirections.
925 base = transport.base734 base = transport.base
926 def find_format(transport):735 def find_format(transport):
927 return transport, BzrDirFormat.find_format(736 return transport, controldir.ControlDirFormat.find_format(
928 transport, _server_formats=_server_formats)737 transport, _server_formats=_server_formats)
929738
930 def redirected(transport, e, redirection_notice):739 def redirected(transport, e, redirection_notice):
@@ -945,17 +754,6 @@
945 BzrDir._check_supported(format, _unsupported)754 BzrDir._check_supported(format, _unsupported)
946 return format.open(transport, _found=True)755 return format.open(transport, _found=True)
947756
948 def open_branch(self, name=None, unsupported=False,
949 ignore_fallbacks=False):
950 """Open the branch object at this BzrDir if one is present.
951
952 If unsupported is True, then no longer supported branch formats can
953 still be opened.
954
955 TODO: static convenience version of this?
956 """
957 raise NotImplementedError(self.open_branch)
958
959 @staticmethod757 @staticmethod
960 def open_containing(url, possible_transports=None):758 def open_containing(url, possible_transports=None):
961 """Open an existing branch which contains url.759 """Open an existing branch which contains url.
@@ -963,7 +761,7 @@
963 :param url: url to search from.761 :param url: url to search from.
964 See open_containing_from_transport for more detail.762 See open_containing_from_transport for more detail.
965 """763 """
966 transport = get_transport(url, possible_transports)764 transport = _mod_transport.get_transport(url, possible_transports)
967 return BzrDir.open_containing_from_transport(transport)765 return BzrDir.open_containing_from_transport(transport)
968766
969 @staticmethod767 @staticmethod
@@ -999,27 +797,6 @@
999 raise errors.NotBranchError(path=url)797 raise errors.NotBranchError(path=url)
1000 a_transport = new_t798 a_transport = new_t
1001799
1002 def _get_tree_branch(self, name=None):
1003 """Return the branch and tree, if any, for this bzrdir.
1004
1005 :param name: Name of colocated branch to open.
1006
1007 Return None for tree if not present or inaccessible.
1008 Raise NotBranchError if no branch is present.
1009 :return: (tree, branch)
1010 """
1011 try:
1012 tree = self.open_workingtree()
1013 except (errors.NoWorkingTree, errors.NotLocalUrl):
1014 tree = None
1015 branch = self.open_branch(name=name)
1016 else:
1017 if name is not None:
1018 branch = self.open_branch(name=name)
1019 else:
1020 branch = tree.branch
1021 return tree, branch
1022
1023 @classmethod800 @classmethod
1024 def open_tree_or_branch(klass, location):801 def open_tree_or_branch(klass, location):
1025 """Return the branch and working tree at a location.802 """Return the branch and working tree at a location.
@@ -1071,59 +848,6 @@
1071 raise errors.NotBranchError(location)848 raise errors.NotBranchError(location)
1072 return tree, branch, branch.repository, relpath849 return tree, branch, branch.repository, relpath
1073850
1074 def open_repository(self, _unsupported=False):
1075 """Open the repository object at this BzrDir if one is present.
1076
1077 This will not follow the Branch object pointer - it's strictly a direct
1078 open facility. Most client code should use open_branch().repository to
1079 get at a repository.
1080
1081 :param _unsupported: a private parameter, not part of the api.
1082 TODO: static convenience version of this?
1083 """
1084 raise NotImplementedError(self.open_repository)
1085
1086 def open_workingtree(self, _unsupported=False,
1087 recommend_upgrade=True, from_branch=None):
1088 """Open the workingtree object at this BzrDir if one is present.
1089
1090 :param recommend_upgrade: Optional keyword parameter, when True (the
1091 default), emit through the ui module a recommendation that the user
1092 upgrade the working tree when the workingtree being opened is old
1093 (but still fully supported).
1094 :param from_branch: override bzrdir branch (for lightweight checkouts)
1095 """
1096 raise NotImplementedError(self.open_workingtree)
1097
1098 def has_branch(self, name=None):
1099 """Tell if this bzrdir contains a branch.
1100
1101 Note: if you're going to open the branch, you should just go ahead
1102 and try, and not ask permission first. (This method just opens the
1103 branch and discards it, and that's somewhat expensive.)
1104 """
1105 try:
1106 self.open_branch(name)
1107 return True
1108 except errors.NotBranchError:
1109 return False
1110
1111 def has_workingtree(self):
1112 """Tell if this bzrdir contains a working tree.
1113
1114 This will still raise an exception if the bzrdir has a workingtree that
1115 is remote & inaccessible.
1116
1117 Note: if you're going to open the working tree, you should just go ahead
1118 and try, and not ask permission first. (This method just opens the
1119 workingtree and discards it, and that's somewhat expensive.)
1120 """
1121 try:
1122 self.open_workingtree(recommend_upgrade=False)
1123 return True
1124 except errors.NoWorkingTree:
1125 return False
1126
1127 def _cloning_metadir(self):851 def _cloning_metadir(self):
1128 """Produce a metadir suitable for cloning with.852 """Produce a metadir suitable for cloning with.
1129853
@@ -1187,192 +911,23 @@
1187 format.require_stacking()911 format.require_stacking()
1188 return format912 return format
1189913
1190 def checkout_metadir(self):914 @classmethod
1191 return self.cloning_metadir()915 def create(cls, base, format=None, possible_transports=None):
1192916 """Create a new BzrDir at the url 'base'.
1193 def sprout(self, url, revision_id=None, force_new_repo=False,917
1194 recurse='down', possible_transports=None,918 :param format: If supplied, the format of branch to create. If not
1195 accelerator_tree=None, hardlink=False, stacked=False,919 supplied, the default is used.
1196 source_branch=None, create_tree_if_local=True):920 :param possible_transports: If supplied, a list of transports that
1197 """Create a copy of this bzrdir prepared for use as a new line of921 can be reused to share a remote connection.
1198 development.
1199
1200 If url's last component does not exist, it will be created.
1201
1202 Attributes related to the identity of the source branch like
1203 branch nickname will be cleaned, a working tree is created
1204 whether one existed before or not; and a local branch is always
1205 created.
1206
1207 if revision_id is not None, then the clone operation may tune
1208 itself to download less data.
1209 :param accelerator_tree: A tree which can be used for retrieving file
1210 contents more quickly than the revision tree, i.e. a workingtree.
1211 The revision tree will be used for cases where accelerator_tree's
1212 content is different.
1213 :param hardlink: If true, hard-link files from accelerator_tree,
1214 where possible.
1215 :param stacked: If true, create a stacked branch referring to the
1216 location of this control directory.
1217 :param create_tree_if_local: If true, a working-tree will be created
1218 when working locally.
1219 """922 """
1220 target_transport = get_transport(url, possible_transports)923 if cls is not BzrDir:
1221 target_transport.ensure_base()924 raise AssertionError("BzrDir.create always creates the"
1222 cloning_format = self.cloning_metadir(stacked)925 "default format, not one of %r" % cls)
1223 # Create/update the result branch926 t = _mod_transport.get_transport(base, possible_transports)
1224 result = cloning_format.initialize_on_transport(target_transport)927 t.ensure_base()
1225 # if a stacked branch wasn't requested, we don't create one928 if format is None:
1226 # even if the origin was stacked929 format = controldir.ControlDirFormat.get_default_format()
1227 stacked_branch_url = None930 return format.initialize_on_transport(t)
1228 if source_branch is not None:
1229 if stacked:
1230 stacked_branch_url = self.root_transport.base
1231 source_repository = source_branch.repository
1232 else:
1233 try:
1234 source_branch = self.open_branch()
1235 source_repository = source_branch.repository
1236 if stacked:
1237 stacked_branch_url = self.root_transport.base
1238 except errors.NotBranchError:
1239 source_branch = None
1240 try:
1241 source_repository = self.open_repository()
1242 except errors.NoRepositoryPresent:
1243 source_repository = None
1244 repository_policy = result.determine_repository_policy(
1245 force_new_repo, stacked_branch_url, require_stacking=stacked)
1246 result_repo, is_new_repo = repository_policy.acquire_repository()
1247 is_stacked = stacked or (len(result_repo._fallback_repositories) != 0)
1248 if is_new_repo and revision_id is not None and not is_stacked:
1249 fetch_spec = graph.PendingAncestryResult(
1250 [revision_id], source_repository)
1251 else:
1252 fetch_spec = None
1253 if source_repository is not None:
1254 # Fetch while stacked to prevent unstacked fetch from
1255 # Branch.sprout.
1256 if fetch_spec is None:
1257 result_repo.fetch(source_repository, revision_id=revision_id)
1258 else:
1259 result_repo.fetch(source_repository, fetch_spec=fetch_spec)
1260
1261 if source_branch is None:
1262 # this is for sprouting a bzrdir without a branch; is that
1263 # actually useful?
1264 # Not especially, but it's part of the contract.
1265 result_branch = result.create_branch()
1266 else:
1267 result_branch = source_branch.sprout(result,
1268 revision_id=revision_id, repository_policy=repository_policy)
1269 mutter("created new branch %r" % (result_branch,))
1270
1271 # Create/update the result working tree
1272 if (create_tree_if_local and
1273 isinstance(target_transport, local.LocalTransport) and
1274 (result_repo is None or result_repo.make_working_trees())):
1275 wt = result.create_workingtree(accelerator_tree=accelerator_tree,
1276 hardlink=hardlink)
1277 wt.lock_write()
1278 try:
1279 if wt.path2id('') is None:
1280 try:
1281 wt.set_root_id(self.open_workingtree.get_root_id())
1282 except errors.NoWorkingTree:
1283 pass
1284 finally:
1285 wt.unlock()
1286 else:
1287 wt = None
1288 if recurse == 'down':
1289 if wt is not None:
1290 basis = wt.basis_tree()
1291 basis.lock_read()
1292 subtrees = basis.iter_references()
1293 elif result_branch is not None:
1294 basis = result_branch.basis_tree()
1295 basis.lock_read()
1296 subtrees = basis.iter_references()
1297 elif source_branch is not None:
1298 basis = source_branch.basis_tree()
1299 basis.lock_read()
1300 subtrees = basis.iter_references()
1301 else:
1302 subtrees = []
1303 basis = None
1304 try:
1305 for path, file_id in subtrees:
1306 target = urlutils.join(url, urlutils.escape(path))
1307 sublocation = source_branch.reference_parent(file_id, path)
1308 sublocation.bzrdir.sprout(target,
1309 basis.get_reference_revision(file_id, path),
1310 force_new_repo=force_new_repo, recurse=recurse,
1311 stacked=stacked)
1312 finally:
1313 if basis is not None:
1314 basis.unlock()
1315 return result
1316
1317 def push_branch(self, source, revision_id=None, overwrite=False,
1318 remember=False, create_prefix=False):
1319 """Push the source branch into this BzrDir."""
1320 br_to = None
1321 # If we can open a branch, use its direct repository, otherwise see
1322 # if there is a repository without a branch.
1323 try:
1324 br_to = self.open_branch()
1325 except errors.NotBranchError:
1326 # Didn't find a branch, can we find a repository?
1327 repository_to = self.find_repository()
1328 else:
1329 # Found a branch, so we must have found a repository
1330 repository_to = br_to.repository
1331
1332 push_result = PushResult()
1333 push_result.source_branch = source
1334 if br_to is None:
1335 # We have a repository but no branch, copy the revisions, and then
1336 # create a branch.
1337 repository_to.fetch(source.repository, revision_id=revision_id)
1338 br_to = source.clone(self, revision_id=revision_id)
1339 if source.get_push_location() is None or remember:
1340 source.set_push_location(br_to.base)
1341 push_result.stacked_on = None
1342 push_result.branch_push_result = None
1343 push_result.old_revno = None
1344 push_result.old_revid = _mod_revision.NULL_REVISION
1345 push_result.target_branch = br_to
1346 push_result.master_branch = None
1347 push_result.workingtree_updated = False
1348 else:
1349 # We have successfully opened the branch, remember if necessary:
1350 if source.get_push_location() is None or remember:
1351 source.set_push_location(br_to.base)
1352 try:
1353 tree_to = self.open_workingtree()
1354 except errors.NotLocalUrl:
1355 push_result.branch_push_result = source.push(br_to,
1356 overwrite, stop_revision=revision_id)
1357 push_result.workingtree_updated = False
1358 except errors.NoWorkingTree:
1359 push_result.branch_push_result = source.push(br_to,
1360 overwrite, stop_revision=revision_id)
1361 push_result.workingtree_updated = None # Not applicable
1362 else:
1363 tree_to.lock_write()
1364 try:
1365 push_result.branch_push_result = source.push(
1366 tree_to.branch, overwrite, stop_revision=revision_id)
1367 tree_to.update()
1368 finally:
1369 tree_to.unlock()
1370 push_result.workingtree_updated = True
1371 push_result.old_revno = push_result.branch_push_result.old_revno
1372 push_result.old_revid = push_result.branch_push_result.old_revid
1373 push_result.target_branch = \
1374 push_result.branch_push_result.target_branch
1375 return push_result
1376931
1377932
1378class BzrDirHooks(hooks.Hooks):933class BzrDirHooks(hooks.Hooks):
@@ -1448,7 +1003,7 @@
1448 def cloning_metadir(self, require_stacking=False):1003 def cloning_metadir(self, require_stacking=False):
1449 """Produce a metadir suitable for cloning with."""1004 """Produce a metadir suitable for cloning with."""
1450 if require_stacking:1005 if require_stacking:
1451 return format_registry.make_bzrdir('1.6')1006 return controldir.format_registry.make_bzrdir('1.6')
1452 return self._format.__class__()1007 return self._format.__class__()
14531008
1454 def clone(self, url, revision_id=None, force_new_repo=False,1009 def clone(self, url, revision_id=None, force_new_repo=False,
@@ -1474,8 +1029,11 @@
1474 tree.clone(result)1029 tree.clone(result)
1475 return result1030 return result
14761031
1477 def create_branch(self, name=None):1032 def create_branch(self, name=None, repository=None):
1478 """See BzrDir.create_branch."""1033 """See BzrDir.create_branch."""
1034 if repository is not None:
1035 raise NotImplementedError(
1036 "create_branch(repository=<not None>) on %r" % (self,))
1479 return self._format.get_branch_format().initialize(self, name=name)1037 return self._format.get_branch_format().initialize(self, name=name)
14801038
1481 def destroy_branch(self, name=None):1039 def destroy_branch(self, name=None):
@@ -1711,9 +1269,10 @@
1711 """See BzrDir.can_convert_format()."""1269 """See BzrDir.can_convert_format()."""
1712 return True1270 return True
17131271
1714 def create_branch(self, name=None):1272 def create_branch(self, name=None, repository=None):
1715 """See BzrDir.create_branch."""1273 """See BzrDir.create_branch."""
1716 return self._format.get_branch_format().initialize(self, name=name)1274 return self._format.get_branch_format().initialize(self, name=name,
1275 repository=repository)
17171276
1718 def destroy_branch(self, name=None):1277 def destroy_branch(self, name=None):
1719 """See BzrDir.create_branch."""1278 """See BzrDir.create_branch."""
@@ -1741,7 +1300,10 @@
1741 wt = self.open_workingtree(recommend_upgrade=False)1300 wt = self.open_workingtree(recommend_upgrade=False)
1742 repository = wt.branch.repository1301 repository = wt.branch.repository
1743 empty = repository.revision_tree(_mod_revision.NULL_REVISION)1302 empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1744 wt.revert(old_tree=empty)1303 # We ignore the conflicts returned by wt.revert since we're about to
1304 # delete the wt metadata anyway, all that should be left here are
1305 # detritus. But see bug #634470 about subtree .bzr dirs.
1306 conflicts = wt.revert(old_tree=empty)
1745 self.destroy_workingtree_metadata()1307 self.destroy_workingtree_metadata()
17461308
1747 def destroy_workingtree_metadata(self):1309 def destroy_workingtree_metadata(self):
@@ -1891,13 +1453,66 @@
1891 return config.TransportConfig(self.transport, 'control.conf')1453 return config.TransportConfig(self.transport, 'control.conf')
18921454
18931455
1894class BzrDirFormat(object):1456class BzrProber(controldir.Prober):
1895 """An encapsulation of the initialization and open routines for a format.1457 """Prober for formats that use a .bzr/ control directory."""
18961458
1897 Formats provide three things:1459 _formats = {}
1898 * An initialization routine,1460 """The known .bzr formats."""
1899 * a format string,1461
1900 * an open routine.1462 @classmethod
1463 def register_bzrdir_format(klass, format):
1464 klass._formats[format.get_format_string()] = format
1465
1466 @classmethod
1467 def unregister_bzrdir_format(klass, format):
1468 del klass._formats[format.get_format_string()]
1469
1470 @classmethod
1471 def probe_transport(klass, transport):
1472 """Return the .bzrdir style format present in a directory."""
1473 try:
1474 format_string = transport.get_bytes(".bzr/branch-format")
1475 except errors.NoSuchFile:
1476 raise errors.NotBranchError(path=transport.base)
1477 try:
1478 return klass._formats[format_string]
1479 except KeyError:
1480 raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
1481
1482
1483controldir.ControlDirFormat.register_prober(BzrProber)
1484
1485
1486class RemoteBzrProber(controldir.Prober):
1487 """Prober for remote servers that provide a Bazaar smart server."""
1488
1489 @classmethod
1490 def probe_transport(klass, transport):
1491 """Return a RemoteBzrDirFormat object if it looks possible."""
1492 try:
1493 medium = transport.get_smart_medium()
1494 except (NotImplementedError, AttributeError,
1495 errors.TransportNotPossible, errors.NoSmartMedium,
1496 errors.SmartProtocolError):
1497 # no smart server, so not a branch for this format type.
1498 raise errors.NotBranchError(path=transport.base)
1499 else:
1500 # Decline to open it if the server doesn't support our required
1501 # version (3) so that the VFS-based transport will do it.
1502 if medium.should_probe():
1503 try:
1504 server_version = medium.protocol_version()
1505 except errors.SmartProtocolError:
1506 # Apparently there's no usable smart server there, even though
1507 # the medium supports the smart protocol.
1508 raise errors.NotBranchError(path=transport.base)
1509 if server_version != '2':
1510 raise errors.NotBranchError(path=transport.base)
1511 return RemoteBzrDirFormat()
1512
1513
1514class BzrDirFormat(controldir.ControlDirFormat):
1515 """ControlDirFormat base class for .bzr/ directories.
19011516
1902 Formats are placed in a dict by their format string for reference1517 Formats are placed in a dict by their format string for reference
1903 during bzrdir opening. These should be subclasses of BzrDirFormat1518 during bzrdir opening. These should be subclasses of BzrDirFormat
@@ -1906,104 +1521,17 @@
1906 Once a format is deprecated, just deprecate the initialize and open1521 Once a format is deprecated, just deprecate the initialize and open
1907 methods on the format class. Do not deprecate the object, as the1522 methods on the format class. Do not deprecate the object, as the
1908 object will be created every system load.1523 object will be created every system load.
1909
1910 :cvar colocated_branches: Whether this formats supports colocated branches.
1911 """
1912
1913 _default_format = None
1914 """The default format used for new .bzr dirs."""
1915
1916 _formats = {}
1917 """The known formats."""
1918
1919 _control_formats = []
1920 """The registered control formats - .bzr, ....
1921
1922 This is a list of BzrDirFormat objects.
1923 """
1924
1925 _control_server_formats = []
1926 """The registered control server formats, e.g. RemoteBzrDirs.
1927
1928 This is a list of BzrDirFormat objects.
1929 """1524 """
19301525
1931 _lock_file_name = 'branch-lock'1526 _lock_file_name = 'branch-lock'
19321527
1933 colocated_branches = False
1934 """Whether co-located branches are supported for this control dir format.
1935 """
1936
1937 # _lock_class must be set in subclasses to the lock type, typ.1528 # _lock_class must be set in subclasses to the lock type, typ.
1938 # TransportLock or LockDir1529 # TransportLock or LockDir
19391530
1940 @classmethod
1941 def find_format(klass, transport, _server_formats=True):
1942 """Return the format present at transport."""
1943 if _server_formats:
1944 formats = klass._control_server_formats + klass._control_formats
1945 else:
1946 formats = klass._control_formats
1947 for format in formats:
1948 try:
1949 return format.probe_transport(transport)
1950 except errors.NotBranchError:
1951 # this format does not find a control dir here.
1952 pass
1953 raise errors.NotBranchError(path=transport.base)
1954
1955 @classmethod
1956 def probe_transport(klass, transport):
1957 """Return the .bzrdir style format present in a directory."""
1958 try:
1959 format_string = transport.get_bytes(".bzr/branch-format")
1960 except errors.NoSuchFile:
1961 raise errors.NotBranchError(path=transport.base)
1962 try:
1963 return klass._formats[format_string]
1964 except KeyError:
1965 raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
1966
1967 @classmethod
1968 def get_default_format(klass):
1969 """Return the current default format."""
1970 return klass._default_format
1971
1972 def get_format_string(self):1531 def get_format_string(self):
1973 """Return the ASCII format string that identifies this format."""1532 """Return the ASCII format string that identifies this format."""
1974 raise NotImplementedError(self.get_format_string)1533 raise NotImplementedError(self.get_format_string)
19751534
1976 def get_format_description(self):
1977 """Return the short description for this format."""
1978 raise NotImplementedError(self.get_format_description)
1979
1980 def get_converter(self, format=None):
1981 """Return the converter to use to convert bzrdirs needing converts.
1982
1983 This returns a bzrlib.bzrdir.Converter object.
1984
1985 This should return the best upgrader to step this format towards the
1986 current default format. In the case of plugins we can/should provide
1987 some means for them to extend the range of returnable converters.
1988
1989 :param format: Optional format to override the default format of the
1990 library.
1991 """
1992 raise NotImplementedError(self.get_converter)
1993
1994 def initialize(self, url, possible_transports=None):
1995 """Create a bzr control dir at this url and return an opened copy.
1996
1997 While not deprecated, this method is very specific and its use will
1998 lead to many round trips to setup a working environment. See
1999 initialize_on_transport_ex for a [nearly] all-in-one method.
2000
2001 Subclasses should typically override initialize_on_transport
2002 instead of this method.
2003 """
2004 return self.initialize_on_transport(get_transport(url,
2005 possible_transports))
2006
2007 def initialize_on_transport(self, transport):1535 def initialize_on_transport(self, transport):
2008 """Initialize a new bzrdir in the base directory of a Transport."""1536 """Initialize a new bzrdir in the base directory of a Transport."""
2009 try:1537 try:
@@ -2141,7 +1669,7 @@
2141 utf8_files = [('README',1669 utf8_files = [('README',
2142 "This is a Bazaar control directory.\n"1670 "This is a Bazaar control directory.\n"
2143 "Do not change any files in this directory.\n"1671 "Do not change any files in this directory.\n"
2144 "See http://bazaar-vcs.org/ for more information about Bazaar.\n"),1672 "See http://bazaar.canonical.com/ for more information about Bazaar.\n"),
2145 ('branch-format', self.get_format_string()),1673 ('branch-format', self.get_format_string()),
2146 ]1674 ]
2147 # NB: no need to escape relative paths that are url safe.1675 # NB: no need to escape relative paths that are url safe.
@@ -2157,55 +1685,13 @@
2157 control_files.unlock()1685 control_files.unlock()
2158 return self.open(transport, _found=True)1686 return self.open(transport, _found=True)
21591687
2160 def is_supported(self):
2161 """Is this format supported?
2162
2163 Supported formats must be initializable and openable.
2164 Unsupported formats may not support initialization or committing or
2165 some other features depending on the reason for not being supported.
2166 """
2167 return True
2168
2169 def network_name(self):
2170 """A simple byte string uniquely identifying this format for RPC calls.
2171
2172 Bzr control formats use thir disk format string to identify the format
2173 over the wire. Its possible that other control formats have more
2174 complex detection requirements, so we permit them to use any unique and
2175 immutable string they desire.
2176 """
2177 raise NotImplementedError(self.network_name)
2178
2179 def same_model(self, target_format):
2180 return (self.repository_format.rich_root_data ==
2181 target_format.rich_root_data)
2182
2183 @classmethod
2184 def known_formats(klass):
2185 """Return all the known formats.
2186
2187 Concrete formats should override _known_formats.
2188 """
2189 # There is double indirection here to make sure that control
2190 # formats used by more than one dir format will only be probed
2191 # once. This can otherwise be quite expensive for remote connections.
2192 result = set()
2193 for format in klass._control_formats:
2194 result.update(format._known_formats())
2195 return result
2196
2197 @classmethod
2198 def _known_formats(klass):
2199 """Return the known format instances for this control format."""
2200 return set(klass._formats.values())
2201
2202 def open(self, transport, _found=False):1688 def open(self, transport, _found=False):
2203 """Return an instance of this format for the dir transport points at.1689 """Return an instance of this format for the dir transport points at.
22041690
2205 _found is a private parameter, do not use it.1691 _found is a private parameter, do not use it.
2206 """1692 """
2207 if not _found:1693 if not _found:
2208 found_format = BzrDirFormat.find_format(transport)1694 found_format = controldir.ControlDirFormat.find_format(transport)
2209 if not isinstance(found_format, self.__class__):1695 if not isinstance(found_format, self.__class__):
2210 raise AssertionError("%s was asked to open %s, but it seems to need "1696 raise AssertionError("%s was asked to open %s, but it seems to need "
2211 "format %s"1697 "format %s"
@@ -2225,40 +1711,10 @@
22251711
2226 @classmethod1712 @classmethod
2227 def register_format(klass, format):1713 def register_format(klass, format):
2228 klass._formats[format.get_format_string()] = format1714 BzrProber.register_bzrdir_format(format)
2229 # bzr native formats have a network name of their format string.1715 # bzr native formats have a network name of their format string.
2230 network_format_registry.register(format.get_format_string(), format.__class__)1716 controldir.network_format_registry.register(format.get_format_string(), format.__class__)
22311717 controldir.ControlDirFormat.register_format(format)
2232 @classmethod
2233 def register_control_format(klass, format):
2234 """Register a format that does not use '.bzr' for its control dir.
2235
2236 TODO: This should be pulled up into a 'ControlDirFormat' base class
2237 which BzrDirFormat can inherit from, and renamed to register_format
2238 there. It has been done without that for now for simplicity of
2239 implementation.
2240 """
2241 klass._control_formats.append(format)
2242
2243 @classmethod
2244 def register_control_server_format(klass, format):
2245 """Register a control format for client-server environments.
2246
2247 These formats will be tried before ones registered with
2248 register_control_format. This gives implementations that decide to the
2249 chance to grab it before anything looks at the contents of the format
2250 file.
2251 """
2252 klass._control_server_formats.append(format)
2253
2254 @classmethod
2255 def _set_default_format(klass, format):
2256 """Set default format (for testing behavior of defaults only)"""
2257 klass._default_format = format
2258
2259 def __str__(self):
2260 # Trim the newline
2261 return self.get_format_description().rstrip()
22621718
2263 def _supply_sub_formats_to(self, other_format):1719 def _supply_sub_formats_to(self, other_format):
2264 """Give other_format the same values for sub formats as this has.1720 """Give other_format the same values for sub formats as this has.
@@ -2274,11 +1730,9 @@
22741730
2275 @classmethod1731 @classmethod
2276 def unregister_format(klass, format):1732 def unregister_format(klass, format):
2277 del klass._formats[format.get_format_string()]1733 BzrProber.unregister_bzrdir_format(format)
22781734 controldir.ControlDirFormat.unregister_format(format)
2279 @classmethod1735 controldir.network_format_registry.remove(format.get_format_string())
2280 def unregister_control_format(klass, format):
2281 klass._control_formats.remove(format)
22821736
22831737
2284class BzrDirFormat4(BzrDirFormat):1738class BzrDirFormat4(BzrDirFormat):
@@ -2392,7 +1846,8 @@
2392 return ConvertBzrDir5To6()1846 return ConvertBzrDir5To6()
23931847
2394 def _initialize_for_clone(self, url):1848 def _initialize_for_clone(self, url):
2395 return self.initialize_on_transport(get_transport(url), _cloning=True)1849 return self.initialize_on_transport(
1850 _mod_transport.get_transport(url), _cloning=True)
23961851
2397 def initialize_on_transport(self, transport, _cloning=False):1852 def initialize_on_transport(self, transport, _cloning=False):
2398 """Format 5 dirs always have working tree, branch and repository.1853 """Format 5 dirs always have working tree, branch and repository.
@@ -2452,7 +1907,8 @@
2452 return ConvertBzrDir6ToMeta()1907 return ConvertBzrDir6ToMeta()
24531908
2454 def _initialize_for_clone(self, url):1909 def _initialize_for_clone(self, url):
2455 return self.initialize_on_transport(get_transport(url), _cloning=True)1910 return self.initialize_on_transport(
1911 _mod_transport.get_transport(url), _cloning=True)
24561912
2457 def initialize_on_transport(self, transport, _cloning=False):1913 def initialize_on_transport(self, transport, _cloning=False):
2458 """Format 6 dirs always have working tree, branch and repository.1914 """Format 6 dirs always have working tree, branch and repository.
@@ -2687,25 +2143,13 @@
2687 __set_workingtree_format)2143 __set_workingtree_format)
26882144
26892145
2690network_format_registry = registry.FormatRegistry()
2691"""Registry of formats indexed by their network name.
2692
2693The network name for a BzrDirFormat is an identifier that can be used when
2694referring to formats with smart server operations. See
2695BzrDirFormat.network_name() for more detail.
2696"""
2697
2698
2699# Register bzr control format
2700BzrDirFormat.register_control_format(BzrDirFormat)
2701
2702# Register bzr formats2146# Register bzr formats
2703BzrDirFormat.register_format(BzrDirFormat4())2147BzrDirFormat.register_format(BzrDirFormat4())
2704BzrDirFormat.register_format(BzrDirFormat5())2148BzrDirFormat.register_format(BzrDirFormat5())
2705BzrDirFormat.register_format(BzrDirFormat6())2149BzrDirFormat.register_format(BzrDirFormat6())
2706__default_format = BzrDirMetaFormat1()2150__default_format = BzrDirMetaFormat1()
2707BzrDirFormat.register_format(__default_format)2151BzrDirFormat.register_format(__default_format)
2708BzrDirFormat._default_format = __default_format2152controldir.ControlDirFormat._default_format = __default_format
27092153
27102154
2711class Converter(object):2155class Converter(object):
@@ -2813,9 +2257,11 @@
2813 mode=self.bzrdir._get_file_mode())2257 mode=self.bzrdir._get_file_mode())
28142258
2815 def _write_all_weaves(self):2259 def _write_all_weaves(self):
2816 controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)2260 controlweaves = VersionedFileStore(self.bzrdir.transport, prefixed=False,
2261 versionedfile_class=WeaveFile)
2817 weave_transport = self.bzrdir.transport.clone('weaves')2262 weave_transport = self.bzrdir.transport.clone('weaves')
2818 weaves = WeaveStore(weave_transport, prefixed=False)2263 weaves = VersionedFileStore(weave_transport, prefixed=False,
2264 versionedfile_class=WeaveFile)
2819 transaction = WriteTransaction()2265 transaction = WriteTransaction()
28202266
2821 try:2267 try:
@@ -2939,7 +2385,6 @@
2939 previous_entries = dict((head, parent_candiate_entries[head]) for head2385 previous_entries = dict((head, parent_candiate_entries[head]) for head
2940 in heads)2386 in heads)
2941 self.snapshot_ie(previous_entries, ie, w, rev_id)2387 self.snapshot_ie(previous_entries, ie, w, rev_id)
2942 del ie.text_id
29432388
2944 def get_parent_map(self, revision_ids):2389 def get_parent_map(self, revision_ids):
2945 """See graph.StackedParentsProvider.get_parent_map"""2390 """See graph.StackedParentsProvider.get_parent_map"""
@@ -3247,6 +2692,8 @@
3247class RemoteBzrDirFormat(BzrDirMetaFormat1):2692class RemoteBzrDirFormat(BzrDirMetaFormat1):
3248 """Format representing bzrdirs accessed via a smart server"""2693 """Format representing bzrdirs accessed via a smart server"""
32492694
2695 supports_workingtrees = False
2696
3250 def __init__(self):2697 def __init__(self):
3251 BzrDirMetaFormat1.__init__(self)2698 BzrDirMetaFormat1.__init__(self)
3252 # XXX: It's a bit ugly that the network name is here, because we'd2699 # XXX: It's a bit ugly that the network name is here, because we'd
@@ -3261,7 +2708,7 @@
32612708
3262 def get_format_description(self):2709 def get_format_description(self):
3263 if self._network_name:2710 if self._network_name:
3264 real_format = network_format_registry.get(self._network_name)2711 real_format = controldir.network_format_registry.get(self._network_name)
3265 return 'Remote: ' + real_format.get_format_description()2712 return 'Remote: ' + real_format.get_format_description()
3266 return 'bzr remote bzrdir'2713 return 'bzr remote bzrdir'
32672714
@@ -3274,30 +2721,6 @@
3274 else:2721 else:
3275 raise AssertionError("No network name set.")2722 raise AssertionError("No network name set.")
32762723
3277 @classmethod
3278 def probe_transport(klass, transport):
3279 """Return a RemoteBzrDirFormat object if it looks possible."""
3280 try:
3281 medium = transport.get_smart_medium()
3282 except (NotImplementedError, AttributeError,
3283 errors.TransportNotPossible, errors.NoSmartMedium,
3284 errors.SmartProtocolError):
3285 # no smart server, so not a branch for this format type.
3286 raise errors.NotBranchError(path=transport.base)
3287 else:
3288 # Decline to open it if the server doesn't support our required
3289 # version (3) so that the VFS-based transport will do it.
3290 if medium.should_probe():
3291 try:
3292 server_version = medium.protocol_version()
3293 except errors.SmartProtocolError:
3294 # Apparently there's no usable smart server there, even though
3295 # the medium supports the smart protocol.
3296 raise errors.NotBranchError(path=transport.base)
3297 if server_version != '2':
3298 raise errors.NotBranchError(path=transport.base)
3299 return klass()
3300
3301 def initialize_on_transport(self, transport):2724 def initialize_on_transport(self, transport):
3302 try:2725 try:
3303 # hand off the request to the smart server2726 # hand off the request to the smart server
@@ -3502,190 +2925,7 @@
3502 BzrDirMetaFormat1._set_repository_format) #.im_func)2925 BzrDirMetaFormat1._set_repository_format) #.im_func)
35032926
35042927
3505BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)2928controldir.ControlDirFormat.register_server_prober(RemoteBzrProber)
3506
3507
3508class BzrDirFormatInfo(object):
3509
3510 def __init__(self, native, deprecated, hidden, experimental):
3511 self.deprecated = deprecated
3512 self.native = native
3513 self.hidden = hidden
3514 self.experimental = experimental
3515
3516
3517class BzrDirFormatRegistry(registry.Registry):
3518 """Registry of user-selectable BzrDir subformats.
3519
3520 Differs from BzrDirFormat._control_formats in that it provides sub-formats,
3521 e.g. BzrDirMeta1 with weave repository. Also, it's more user-oriented.
3522 """
3523
3524 def __init__(self):
3525 """Create a BzrDirFormatRegistry."""
3526 self._aliases = set()
3527 self._registration_order = list()
3528 super(BzrDirFormatRegistry, self).__init__()
3529
3530 def aliases(self):
3531 """Return a set of the format names which are aliases."""
3532 return frozenset(self._aliases)
3533
3534 def register_metadir(self, key,
3535 repository_format, help, native=True, deprecated=False,
3536 branch_format=None,
3537 tree_format=None,
3538 hidden=False,
3539 experimental=False,
3540 alias=False):
3541 """Register a metadir subformat.
3542
3543 These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
3544 by the Repository/Branch/WorkingTreeformats.
3545
3546 :param repository_format: The fully-qualified repository format class
3547 name as a string.
3548 :param branch_format: Fully-qualified branch format class name as
3549 a string.
3550 :param tree_format: Fully-qualified tree format class name as
3551 a string.
3552 """
3553 # This should be expanded to support setting WorkingTree and Branch
3554 # formats, once BzrDirMetaFormat1 supports that.
3555 def _load(full_name):
3556 mod_name, factory_name = full_name.rsplit('.', 1)
3557 try:
3558 mod = __import__(mod_name, globals(), locals(),
3559 [factory_name])
3560 except ImportError, e:
3561 raise ImportError('failed to load %s: %s' % (full_name, e))
3562 try:
3563 factory = getattr(mod, factory_name)
3564 except AttributeError:
3565 raise AttributeError('no factory %s in module %r'
3566 % (full_name, mod))
3567 return factory()
3568
3569 def helper():
3570 bd = BzrDirMetaFormat1()
3571 if branch_format is not None:
3572 bd.set_branch_format(_load(branch_format))
3573 if tree_format is not None:
3574 bd.workingtree_format = _load(tree_format)
3575 if repository_format is not None:
3576 bd.repository_format = _load(repository_format)
3577 return bd
3578 self.register(key, helper, help, native, deprecated, hidden,
3579 experimental, alias)
3580
3581 def register(self, key, factory, help, native=True, deprecated=False,
3582 hidden=False, experimental=False, alias=False):
3583 """Register a BzrDirFormat factory.
3584
3585 The factory must be a callable that takes one parameter: the key.
3586 It must produce an instance of the BzrDirFormat when called.
3587
3588 This function mainly exists to prevent the info object from being
3589 supplied directly.
3590 """
3591 registry.Registry.register(self, key, factory, help,
3592 BzrDirFormatInfo(native, deprecated, hidden, experimental))
3593 if alias:
3594 self._aliases.add(key)
3595 self._registration_order.append(key)
3596
3597 def register_lazy(self, key, module_name, member_name, help, native=True,
3598 deprecated=False, hidden=False, experimental=False, alias=False):
3599 registry.Registry.register_lazy(self, key, module_name, member_name,
3600 help, BzrDirFormatInfo(native, deprecated, hidden, experimental))
3601 if alias:
3602 self._aliases.add(key)
3603 self._registration_order.append(key)
3604
3605 def set_default(self, key):
3606 """Set the 'default' key to be a clone of the supplied key.
3607
3608 This method must be called once and only once.
3609 """
3610 registry.Registry.register(self, 'default', self.get(key),
3611 self.get_help(key), info=self.get_info(key))
3612 self._aliases.add('default')
3613
3614 def set_default_repository(self, key):
3615 """Set the FormatRegistry default and Repository default.
3616
3617 This is a transitional method while Repository.set_default_format
3618 is deprecated.
3619 """
3620 if 'default' in self:
3621 self.remove('default')
3622 self.set_default(key)
3623 format = self.get('default')()
3624
3625 def make_bzrdir(self, key):
3626 return self.get(key)()
3627
3628 def help_topic(self, topic):
3629 output = ""
3630 default_realkey = None
3631 default_help = self.get_help('default')
3632 help_pairs = []
3633 for key in self._registration_order:
3634 if key == 'default':
3635 continue
3636 help = self.get_help(key)
3637 if help == default_help:
3638 default_realkey = key
3639 else:
3640 help_pairs.append((key, help))
3641
3642 def wrapped(key, help, info):
3643 if info.native:
3644 help = '(native) ' + help
3645 return ':%s:\n%s\n\n' % (key,
3646 textwrap.fill(help, initial_indent=' ',
3647 subsequent_indent=' ',
3648 break_long_words=False))
3649 if default_realkey is not None:
3650 output += wrapped(default_realkey, '(default) %s' % default_help,
3651 self.get_info('default'))
3652 deprecated_pairs = []
3653 experimental_pairs = []
3654 for key, help in help_pairs:
3655 info = self.get_info(key)
3656 if info.hidden:
3657 continue
3658 elif info.deprecated:
3659 deprecated_pairs.append((key, help))
3660 elif info.experimental:
3661 experimental_pairs.append((key, help))
3662 else:
3663 output += wrapped(key, help, info)
3664 output += "\nSee :doc:`formats-help` for more about storage formats."
3665 other_output = ""
3666 if len(experimental_pairs) > 0:
3667 other_output += "Experimental formats are shown below.\n\n"
3668 for key, help in experimental_pairs:
3669 info = self.get_info(key)
3670 other_output += wrapped(key, help, info)
3671 else:
3672 other_output += \
3673 "No experimental formats are available.\n\n"
3674 if len(deprecated_pairs) > 0:
3675 other_output += "\nDeprecated formats are shown below.\n\n"
3676 for key, help in deprecated_pairs:
3677 info = self.get_info(key)
3678 other_output += wrapped(key, help, info)
3679 else:
3680 other_output += \
3681 "\nNo deprecated formats are available.\n\n"
3682 other_output += \
3683 "\nSee :doc:`formats-help` for more about storage formats."
3684
3685 if topic == 'other-formats':
3686 return other_output
3687 else:
3688 return output
36892929
36902930
3691class RepositoryAcquisitionPolicy(object):2931class RepositoryAcquisitionPolicy(object):
@@ -3845,33 +3085,73 @@
3845 return self._repository, False3085 return self._repository, False
38463086
38473087
3848# Please register new formats after old formats so that formats3088def register_metadir(registry, key,
3849# appear in chronological order and format descriptions can build3089 repository_format, help, native=True, deprecated=False,
3850# on previous ones.3090 branch_format=None,
3851format_registry = BzrDirFormatRegistry()3091 tree_format=None,
3092 hidden=False,
3093 experimental=False,
3094 alias=False):
3095 """Register a metadir subformat.
3096
3097 These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
3098 by the Repository/Branch/WorkingTreeformats.
3099
3100 :param repository_format: The fully-qualified repository format class
3101 name as a string.
3102 :param branch_format: Fully-qualified branch format class name as
3103 a string.
3104 :param tree_format: Fully-qualified tree format class name as
3105 a string.
3106 """
3107 # This should be expanded to support setting WorkingTree and Branch
3108 # formats, once BzrDirMetaFormat1 supports that.
3109 def _load(full_name):
3110 mod_name, factory_name = full_name.rsplit('.', 1)
3111 try:
3112 factory = pyutils.get_named_object(mod_name, factory_name)
3113 except ImportError, e:
3114 raise ImportError('failed to load %s: %s' % (full_name, e))
3115 except AttributeError:
3116 raise AttributeError('no factory %s in module %r'
3117 % (full_name, sys.modules[mod_name]))
3118 return factory()
3119
3120 def helper():
3121 bd = BzrDirMetaFormat1()
3122 if branch_format is not None:
3123 bd.set_branch_format(_load(branch_format))
3124 if tree_format is not None:
3125 bd.workingtree_format = _load(tree_format)
3126 if repository_format is not None:
3127 bd.repository_format = _load(repository_format)
3128 return bd
3129 registry.register(key, helper, help, native, deprecated, hidden,
3130 experimental, alias)
3131
3852# The pre-0.8 formats have their repository format network name registered in3132# The pre-0.8 formats have their repository format network name registered in
3853# repository.py. MetaDir formats have their repository format network name3133# repository.py. MetaDir formats have their repository format network name
3854# inferred from their disk format string.3134# inferred from their disk format string.
3855format_registry.register('weave', BzrDirFormat6,3135controldir.format_registry.register('weave', BzrDirFormat6,
3856 'Pre-0.8 format. Slower than knit and does not'3136 'Pre-0.8 format. Slower than knit and does not'
3857 ' support checkouts or shared repositories.',3137 ' support checkouts or shared repositories.',
3858 hidden=True,3138 hidden=True,
3859 deprecated=True)3139 deprecated=True)
3860format_registry.register_metadir('metaweave',3140register_metadir(controldir.format_registry, 'metaweave',
3861 'bzrlib.repofmt.weaverepo.RepositoryFormat7',3141 'bzrlib.repofmt.weaverepo.RepositoryFormat7',
3862 'Transitional format in 0.8. Slower than knit.',3142 'Transitional format in 0.8. Slower than knit.',
3863 branch_format='bzrlib.branch.BzrBranchFormat5',3143 branch_format='bzrlib.branch.BzrBranchFormat5',
3864 tree_format='bzrlib.workingtree.WorkingTreeFormat3',3144 tree_format='bzrlib.workingtree.WorkingTreeFormat3',
3865 hidden=True,3145 hidden=True,
3866 deprecated=True)3146 deprecated=True)
3867format_registry.register_metadir('knit',3147register_metadir(controldir.format_registry, 'knit',
3868 'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',3148 'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
3869 'Format using knits. Recommended for interoperation with bzr <= 0.14.',3149 'Format using knits. Recommended for interoperation with bzr <= 0.14.',
3870 branch_format='bzrlib.branch.BzrBranchFormat5',3150 branch_format='bzrlib.branch.BzrBranchFormat5',
3871 tree_format='bzrlib.workingtree.WorkingTreeFormat3',3151 tree_format='bzrlib.workingtree.WorkingTreeFormat3',
3872 hidden=True,3152 hidden=True,
3873 deprecated=True)3153 deprecated=True)
3874format_registry.register_metadir('dirstate',3154register_metadir(controldir.format_registry, 'dirstate',
3875 'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',3155 'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
3876 help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '3156 help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
3877 'above when accessed over the network.',3157 'above when accessed over the network.',
@@ -3881,7 +3161,7 @@
3881 tree_format='bzrlib.workingtree.WorkingTreeFormat4',3161 tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3882 hidden=True,3162 hidden=True,
3883 deprecated=True)3163 deprecated=True)
3884format_registry.register_metadir('dirstate-tags',3164register_metadir(controldir.format_registry, 'dirstate-tags',
3885 'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',3165 'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
3886 help='New in 0.15: Fast local operations and improved scaling for '3166 help='New in 0.15: Fast local operations and improved scaling for '
3887 'network operations. Additionally adds support for tags.'3167 'network operations. Additionally adds support for tags.'
@@ -3890,7 +3170,7 @@
3890 tree_format='bzrlib.workingtree.WorkingTreeFormat4',3170 tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3891 hidden=True,3171 hidden=True,
3892 deprecated=True)3172 deprecated=True)
3893format_registry.register_metadir('rich-root',3173register_metadir(controldir.format_registry, 'rich-root',
3894 'bzrlib.repofmt.knitrepo.RepositoryFormatKnit4',3174 'bzrlib.repofmt.knitrepo.RepositoryFormatKnit4',
3895 help='New in 1.0. Better handling of tree roots. Incompatible with'3175 help='New in 1.0. Better handling of tree roots. Incompatible with'
3896 ' bzr < 1.0.',3176 ' bzr < 1.0.',
@@ -3898,7 +3178,7 @@
3898 tree_format='bzrlib.workingtree.WorkingTreeFormat4',3178 tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3899 hidden=True,3179 hidden=True,
3900 deprecated=True)3180 deprecated=True)
3901format_registry.register_metadir('dirstate-with-subtree',3181register_metadir(controldir.format_registry, 'dirstate-with-subtree',
3902 'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',3182 'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
3903 help='New in 0.15: Fast local operations and improved scaling for '3183 help='New in 0.15: Fast local operations and improved scaling for '
3904 'network operations. Additionally adds support for versioning nested '3184 'network operations. Additionally adds support for versioning nested '
@@ -3908,7 +3188,7 @@
3908 experimental=True,3188 experimental=True,
3909 hidden=True,3189 hidden=True,
3910 )3190 )
3911format_registry.register_metadir('pack-0.92',3191register_metadir(controldir.format_registry, 'pack-0.92',
3912 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack1',3192 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack1',
3913 help='New in 0.92: Pack-based format with data compatible with '3193 help='New in 0.92: Pack-based format with data compatible with '
3914 'dirstate-tags format repositories. Interoperates with '3194 'dirstate-tags format repositories. Interoperates with '
@@ -3917,7 +3197,7 @@
3917 branch_format='bzrlib.branch.BzrBranchFormat6',3197 branch_format='bzrlib.branch.BzrBranchFormat6',
3918 tree_format='bzrlib.workingtree.WorkingTreeFormat4',3198 tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3919 )3199 )
3920format_registry.register_metadir('pack-0.92-subtree',3200register_metadir(controldir.format_registry, 'pack-0.92-subtree',
3921 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack3',3201 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack3',
3922 help='New in 0.92: Pack-based format with data compatible with '3202 help='New in 0.92: Pack-based format with data compatible with '
3923 'dirstate-with-subtree format repositories. Interoperates with '3203 'dirstate-with-subtree format repositories. Interoperates with '
@@ -3928,7 +3208,7 @@
3928 hidden=True,3208 hidden=True,
3929 experimental=True,3209 experimental=True,
3930 )3210 )
3931format_registry.register_metadir('rich-root-pack',3211register_metadir(controldir.format_registry, 'rich-root-pack',
3932 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack4',3212 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack4',
3933 help='New in 1.0: A variant of pack-0.92 that supports rich-root data '3213 help='New in 1.0: A variant of pack-0.92 that supports rich-root data '
3934 '(needed for bzr-svn and bzr-git).',3214 '(needed for bzr-svn and bzr-git).',
@@ -3936,7 +3216,7 @@
3936 tree_format='bzrlib.workingtree.WorkingTreeFormat4',3216 tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3937 hidden=True,3217 hidden=True,
3938 )3218 )
3939format_registry.register_metadir('1.6',3219register_metadir(controldir.format_registry, '1.6',
3940 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack5',3220 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack5',
3941 help='A format that allows a branch to indicate that there is another '3221 help='A format that allows a branch to indicate that there is another '
3942 '(stacked) repository that should be used to access data that is '3222 '(stacked) repository that should be used to access data that is '
@@ -3945,7 +3225,7 @@
3945 tree_format='bzrlib.workingtree.WorkingTreeFormat4',3225 tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3946 hidden=True,3226 hidden=True,
3947 )3227 )
3948format_registry.register_metadir('1.6.1-rich-root',3228register_metadir(controldir.format_registry, '1.6.1-rich-root',
3949 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack5RichRoot',3229 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack5RichRoot',
3950 help='A variant of 1.6 that supports rich-root data '3230 help='A variant of 1.6 that supports rich-root data '
3951 '(needed for bzr-svn and bzr-git).',3231 '(needed for bzr-svn and bzr-git).',
@@ -3953,7 +3233,7 @@
3953 tree_format='bzrlib.workingtree.WorkingTreeFormat4',3233 tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3954 hidden=True,3234 hidden=True,
3955 )3235 )
3956format_registry.register_metadir('1.9',3236register_metadir(controldir.format_registry, '1.9',
3957 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6',3237 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6',
3958 help='A repository format using B+tree indexes. These indexes '3238 help='A repository format using B+tree indexes. These indexes '
3959 'are smaller in size, have smarter caching and provide faster '3239 'are smaller in size, have smarter caching and provide faster '
@@ -3962,7 +3242,7 @@
3962 tree_format='bzrlib.workingtree.WorkingTreeFormat4',3242 tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3963 hidden=True,3243 hidden=True,
3964 )3244 )
3965format_registry.register_metadir('1.9-rich-root',3245register_metadir(controldir.format_registry, '1.9-rich-root',
3966 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6RichRoot',3246 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6RichRoot',
3967 help='A variant of 1.9 that supports rich-root data '3247 help='A variant of 1.9 that supports rich-root data '
3968 '(needed for bzr-svn and bzr-git).',3248 '(needed for bzr-svn and bzr-git).',
@@ -3970,13 +3250,13 @@
3970 tree_format='bzrlib.workingtree.WorkingTreeFormat4',3250 tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3971 hidden=True,3251 hidden=True,
3972 )3252 )
3973format_registry.register_metadir('1.14',3253register_metadir(controldir.format_registry, '1.14',
3974 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6',3254 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6',
3975 help='A working-tree format that supports content filtering.',3255 help='A working-tree format that supports content filtering.',
3976 branch_format='bzrlib.branch.BzrBranchFormat7',3256 branch_format='bzrlib.branch.BzrBranchFormat7',
3977 tree_format='bzrlib.workingtree.WorkingTreeFormat5',3257 tree_format='bzrlib.workingtree.WorkingTreeFormat5',
3978 )3258 )
3979format_registry.register_metadir('1.14-rich-root',3259register_metadir(controldir.format_registry, '1.14-rich-root',
3980 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6RichRoot',3260 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6RichRoot',
3981 help='A variant of 1.14 that supports rich-root data '3261 help='A variant of 1.14 that supports rich-root data '
3982 '(needed for bzr-svn and bzr-git).',3262 '(needed for bzr-svn and bzr-git).',
@@ -3984,22 +3264,8 @@
3984 tree_format='bzrlib.workingtree.WorkingTreeFormat5',3264 tree_format='bzrlib.workingtree.WorkingTreeFormat5',
3985 )3265 )
3986# The following un-numbered 'development' formats should always just be aliases.3266# The following un-numbered 'development' formats should always just be aliases.
3987format_registry.register_metadir('development-rich-root',3267register_metadir(controldir.format_registry, 'development-subtree',
3988 'bzrlib.repofmt.groupcompress_repo.RepositoryFormatCHK1',3268 'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2aSubtree',
3989 help='Current development format. Supports rich roots. Can convert data '
3990 'to and from rich-root-pack (and anything compatible with '
3991 'rich-root-pack) format repositories. Repositories and branches in '
3992 'this format can only be read by bzr.dev. Please read '
3993 'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
3994 'before use.',
3995 branch_format='bzrlib.branch.BzrBranchFormat7',
3996 tree_format='bzrlib.workingtree.WorkingTreeFormat6',
3997 experimental=True,
3998 alias=True,
3999 hidden=True,
4000 )
4001format_registry.register_metadir('development-subtree',
4002 'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2Subtree',
4003 help='Current development format, subtree variant. Can convert data to and '3269 help='Current development format, subtree variant. Can convert data to and '
4004 'from pack-0.92-subtree (and anything compatible with '3270 'from pack-0.92-subtree (and anything compatible with '
4005 'pack-0.92-subtree) format repositories. Repositories and branches in '3271 'pack-0.92-subtree) format repositories. Repositories and branches in '
@@ -4014,33 +3280,25 @@
4014 # This current non-alias status is simply because we did not introduce a3280 # This current non-alias status is simply because we did not introduce a
4015 # chk based subtree format.3281 # chk based subtree format.
4016 )3282 )
3283register_metadir(controldir.format_registry, 'development5-subtree',
3284 'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2Subtree',
3285 help='Development format, subtree variant. Can convert data to and '
3286 'from pack-0.92-subtree (and anything compatible with '
3287 'pack-0.92-subtree) format repositories. Repositories and branches in '
3288 'this format can only be read by bzr.dev. Please read '
3289 'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
3290 'before use.',
3291 branch_format='bzrlib.branch.BzrBranchFormat7',
3292 tree_format='bzrlib.workingtree.WorkingTreeFormat6',
3293 experimental=True,
3294 hidden=True,
3295 alias=False,
3296 )
40173297
4018# And the development formats above will have aliased one of the following:3298# And the development formats above will have aliased one of the following:
4019format_registry.register_metadir('development6-rich-root',3299
4020 'bzrlib.repofmt.groupcompress_repo.RepositoryFormatCHK1',3300# Finally, the current format.
4021 help='pack-1.9 with 255-way hashed CHK inv, group compress, rich roots '3301register_metadir(controldir.format_registry, '2a',
4022 'Please read '
4023 'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
4024 'before use.',
4025 branch_format='bzrlib.branch.BzrBranchFormat7',
4026 tree_format='bzrlib.workingtree.WorkingTreeFormat6',
4027 hidden=True,
4028 experimental=True,
4029 )
4030
4031format_registry.register_metadir('development7-rich-root',
4032 'bzrlib.repofmt.groupcompress_repo.RepositoryFormatCHK2',
4033 help='pack-1.9 with 255-way hashed CHK inv, bencode revision, group compress, '
4034 'rich roots. Please read '
4035 'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
4036 'before use.',
4037 branch_format='bzrlib.branch.BzrBranchFormat7',
4038 tree_format='bzrlib.workingtree.WorkingTreeFormat6',
4039 hidden=True,
4040 experimental=True,
4041 )
4042
4043format_registry.register_metadir('2a',
4044 'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2a',3302 'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2a',
4045 help='First format for bzr 2.0 series.\n'3303 help='First format for bzr 2.0 series.\n'
4046 'Uses group-compress storage.\n'3304 'Uses group-compress storage.\n'
@@ -4049,12 +3307,12 @@
4049 # 'rich roots. Supported by bzr 1.16 and later.',3307 # 'rich roots. Supported by bzr 1.16 and later.',
4050 branch_format='bzrlib.branch.BzrBranchFormat7',3308 branch_format='bzrlib.branch.BzrBranchFormat7',
4051 tree_format='bzrlib.workingtree.WorkingTreeFormat6',3309 tree_format='bzrlib.workingtree.WorkingTreeFormat6',
4052 experimental=True,3310 experimental=False,
4053 )3311 )
40543312
4055# The following format should be an alias for the rich root equivalent 3313# The following format should be an alias for the rich root equivalent
4056# of the default format3314# of the default format
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches