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