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