Merge lp:~vila/bzr/747050-config-help into lp:bzr

Proposed by Vincent Ladeuil
Status: Merged
Approved by: Jelmer Vernooij
Approved revision: no longer in the source branch.
Merged at revision: 6072
Proposed branch: lp:~vila/bzr/747050-config-help
Merge into: lp:bzr
Diff against target: 323 lines (+103/-45)
8 files modified
bzrlib/config.py (+16/-8)
bzrlib/help.py (+2/-1)
bzrlib/help_topics/__init__.py (+39/-14)
bzrlib/help_topics/en/configuration.txt (+2/-2)
bzrlib/plugin.py (+3/-12)
bzrlib/tests/test_help.py (+34/-5)
bzrlib/tests/test_plugins.py (+4/-3)
doc/en/release-notes/bzr-2.5.txt (+3/-0)
To merge this branch: bzr merge lp:~vila/bzr/747050-config-help
Reviewer Review Type Date Requested Status
Jelmer Vernooij (community) Needs Fixing
Review via email: mp+70929@code.launchpad.net

Commit message

Implement per-config option help

Description of the change

This implements help topics for registered configuration options.

I refrained from refactoring too much (still reducing the code
duplication a bit) but some love seems to be needed in this area.

I haven't deleted the text from help_topics/configuration.txt
yet, that would be better addressed when fixing bug #746993.

To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) wrote :

TestConfigOptiondIndex seems like it has an extra 'd' :)

TestConfigOptionHelp seems unused.

review: Needs Fixing
Revision history for this message
Vincent Ladeuil (vila) wrote :

sent to pqm by email

Revision history for this message
Vincent Ladeuil (vila) wrote :

sent to pqm by email

Revision history for this message
Vincent Ladeuil (vila) wrote :

sent to pqm by email

Revision history for this message
Vincent Ladeuil (vila) wrote :

sent to pqm by email

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bzrlib/config.py'
--- bzrlib/config.py 2011-08-13 03:39:24 +0000
+++ bzrlib/config.py 2011-08-16 07:35:26 +0000
@@ -2307,6 +2307,15 @@
2307 def get_default(self):2307 def get_default(self):
2308 return self.default2308 return self.default
23092309
2310 def get_help_text(self, additional_see_also=None, plain=True):
2311 result = self.help
2312 from bzrlib import help_topics
2313 result += help_topics._format_see_also(additional_see_also)
2314 if plain:
2315 result = help_topics.help_as_plain_text(result)
2316 return result
2317
2318
2310# Predefined converters to get proper values from store2319# Predefined converters to get proper values from store
23112320
2312def bool_from_store(unicode_str):2321def bool_from_store(unicode_str):
@@ -2351,13 +2360,12 @@
2351 def register_lazy(self, key, module_name, member_name):2360 def register_lazy(self, key, module_name, member_name):
2352 """Register a new option to be loaded on request.2361 """Register a new option to be loaded on request.
23532362
2354 :param key: This is the key to use to request the option later. Since2363 :param key: the key to request the option later. Since the registration
2355 the registration is lazy, it should be provided and match the2364 is lazy, it should be provided and match the option name.
2356 option name.2365
23572366 :param module_name: the python path to the module. Such as 'os.path'.
2358 :param module_name: The python path to the module. Such as 'os.path'.2367
23592368 :param member_name: the member of the module to return. If empty or
2360 :param member_name: The member of the module to return. If empty or
2361 None, get() will return the module itself.2369 None, get() will return the module itself.
2362 """2370 """
2363 super(OptionRegistry, self).register_lazy(key,2371 super(OptionRegistry, self).register_lazy(key,
@@ -2379,7 +2387,7 @@
23792387
2380option_registry.register(2388option_registry.register(
2381 Option('dirstate.fdatasync', default=True, from_unicode=bool_from_store,2389 Option('dirstate.fdatasync', default=True, from_unicode=bool_from_store,
2382 help='''2390 help='''\
2383Flush dirstate changes onto physical disk?2391Flush dirstate changes onto physical disk?
23842392
2385If true (default), working tree metadata changes are flushed through the2393If true (default), working tree metadata changes are flushed through the
23862394
=== modified file 'bzrlib/help.py'
--- bzrlib/help.py 2011-05-18 18:32:22 +0000
+++ bzrlib/help.py 2011-08-16 07:35:26 +0000
@@ -1,4 +1,4 @@
1# Copyright (C) 2005-2010 Canonical Ltd1# Copyright (C) 2005-2011 Canonical Ltd
2#2#
3# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -135,6 +135,7 @@
135 help_topics.HelpTopicIndex(),135 help_topics.HelpTopicIndex(),
136 _mod_commands.HelpCommandIndex(),136 _mod_commands.HelpCommandIndex(),
137 plugin.PluginsHelpIndex(),137 plugin.PluginsHelpIndex(),
138 help_topics.ConfigOptionHelpIndex(),
138 ]139 ]
139140
140 def _check_prefix_uniqueness(self):141 def _check_prefix_uniqueness(self):
141142
=== modified file 'bzrlib/help_topics/__init__.py'
--- bzrlib/help_topics/__init__.py 2011-06-30 16:47:06 +0000
+++ bzrlib/help_topics/__init__.py 2011-08-16 07:35:26 +0000
@@ -1,4 +1,4 @@
1# Copyright (C) 2006-2010 Canonical Ltd1# Copyright (C) 2006-2011 Canonical Ltd
2#2#
3# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -37,6 +37,7 @@
3737
38import bzrlib38import bzrlib
39from bzrlib import (39from bzrlib import (
40 config,
40 osutils,41 osutils,
41 registry,42 registry,
42 )43 )
@@ -65,7 +66,7 @@
65 :param section: Section in reference manual - see SECT_* identifiers.66 :param section: Section in reference manual - see SECT_* identifiers.
66 """67 """
67 # The detail is stored as the 'object' and the metadata as the info68 # The detail is stored as the 'object' and the metadata as the info
68 info=(summary,section)69 info = (summary, section)
69 super(HelpTopicRegistry, self).register(topic, detail, info=info)70 super(HelpTopicRegistry, self).register(topic, detail, info=info)
7071
71 def register_lazy(self, topic, module_name, member_name, summary,72 def register_lazy(self, topic, module_name, member_name, summary,
@@ -79,7 +80,7 @@
79 :param section: Section in reference manual - see SECT_* identifiers.80 :param section: Section in reference manual - see SECT_* identifiers.
80 """81 """
81 # The detail is stored as the 'object' and the metadata as the info82 # The detail is stored as the 'object' and the metadata as the info
82 info=(summary,section)83 info = (summary, section)
83 super(HelpTopicRegistry, self).register_lazy(topic, module_name,84 super(HelpTopicRegistry, self).register_lazy(topic, module_name,
84 member_name, info=info)85 member_name, info=info)
8586
@@ -844,6 +845,15 @@
844 return []845 return []
845846
846847
848def _format_see_also(see_also):
849 result = ''
850 if see_also:
851 result += '\n:See also: '
852 result += ', '.join(sorted(set(see_also)))
853 result += '\n'
854 return result
855
856
847class RegisteredTopic(object):857class RegisteredTopic(object):
848 """A help topic which has been registered in the HelpTopicRegistry.858 """A help topic which has been registered in the HelpTopicRegistry.
849859
@@ -867,17 +877,7 @@
867 returned instead of plain text.877 returned instead of plain text.
868 """878 """
869 result = topic_registry.get_detail(self.topic)879 result = topic_registry.get_detail(self.topic)
870 # there is code duplicated here and in bzrlib/plugin.py's880 result += _format_see_also(additional_see_also)
871 # matching Topic code. This should probably be factored in
872 # to a helper function and a common base class.
873 if additional_see_also is not None:
874 see_also = sorted(set(additional_see_also))
875 else:
876 see_also = None
877 if see_also:
878 result += '\n:See also: '
879 result += ', '.join(see_also)
880 result += '\n'
881 if plain:881 if plain:
882 result = help_as_plain_text(result)882 result = help_as_plain_text(result)
883 return result883 return result
@@ -903,3 +903,28 @@
903 line = re.sub(":doc:`(.+?)-help`", r'``bzr help \1``', line)903 line = re.sub(":doc:`(.+?)-help`", r'``bzr help \1``', line)
904 result.append(line)904 result.append(line)
905 return "\n".join(result) + "\n"905 return "\n".join(result) + "\n"
906
907
908class ConfigOptionHelpIndex(object):
909 """A help index that returns help topics for config options."""
910
911 def __init__(self):
912 self.prefix = 'configuration/'
913
914 def get_topics(self, topic):
915 """Search for topic in the registered config options.
916
917 :param topic: A topic to search for.
918 :return: A list which is either empty or contains a single
919 config.Option entry.
920 """
921 if topic is None:
922 return []
923 elif topic.startswith(self.prefix):
924 topic = topic[len(self.prefix):]
925 if topic in config.option_registry:
926 return [config.option_registry.get(topic)]
927 else:
928 return []
929
930
906931
=== modified file 'bzrlib/help_topics/en/configuration.txt'
--- bzrlib/help_topics/en/configuration.txt 2011-08-02 01:10:27 +0000
+++ bzrlib/help_topics/en/configuration.txt 2011-08-16 07:35:26 +0000
@@ -14,7 +14,7 @@
1414
15 "John Doe <jdoe@example.com>"15 "John Doe <jdoe@example.com>"
1616
17See also the ``email`` configuration value.17See also the ``email`` configuration option.
1818
19BZR_PROGRESS_BAR19BZR_PROGRESS_BAR
20~~~~~~~~~~~~~~~~20~~~~~~~~~~~~~~~~
@@ -54,7 +54,7 @@
5454
55Path to the Bazaar executable to use when using the bzr+ssh protocol.55Path to the Bazaar executable to use when using the bzr+ssh protocol.
5656
57See also the ``bzr_remote_path`` configuration value.57See also the ``bzr_remote_path`` configuration option.
5858
59BZR_EDITOR59BZR_EDITOR
60~~~~~~~~~~60~~~~~~~~~~
6161
=== modified file 'bzrlib/plugin.py'
--- bzrlib/plugin.py 2011-05-31 06:15:24 +0000
+++ bzrlib/plugin.py 2011-08-16 07:35:26 +0000
@@ -506,21 +506,12 @@
506 result = self.module.__doc__506 result = self.module.__doc__
507 if result[-1] != '\n':507 if result[-1] != '\n':
508 result += '\n'508 result += '\n'
509 # there is code duplicated here and in bzrlib/help_topic.py's509 from bzrlib import help_topics
510 # matching Topic code. This should probably be factored in510 result += help_topics._format_see_also(additional_see_also)
511 # to a helper function and a common base class.
512 if additional_see_also is not None:
513 see_also = sorted(set(additional_see_also))
514 else:
515 see_also = None
516 if see_also:
517 result += 'See also: '
518 result += ', '.join(see_also)
519 result += '\n'
520 return result511 return result
521512
522 def get_help_topic(self):513 def get_help_topic(self):
523 """Return the modules help topic - its __name__ after bzrlib.plugins.."""514 """Return the module help topic: its basename."""
524 return self.module.__name__[len('bzrlib.plugins.'):]515 return self.module.__name__[len('bzrlib.plugins.'):]
525516
526517
527518
=== modified file 'bzrlib/tests/test_help.py'
--- bzrlib/tests/test_help.py 2011-06-27 15:36:58 +0000
+++ bzrlib/tests/test_help.py 2011-08-16 07:35:26 +0000
@@ -21,6 +21,7 @@
21from bzrlib import (21from bzrlib import (
22 builtins,22 builtins,
23 commands,23 commands,
24 config,
24 errors,25 errors,
25 help,26 help,
26 help_topics,27 help_topics,
@@ -561,6 +562,31 @@
561 self.assertEqual('', index.prefix)562 self.assertEqual('', index.prefix)
562563
563564
565class TestConfigOptionIndex(TestHelp):
566 """Tests for the HelpCommandIndex class."""
567
568 def setUp(self):
569 super(TestConfigOptionIndex, self).setUp()
570 self.index = help_topics.ConfigOptionHelpIndex()
571
572 def test_get_topics_None(self):
573 """Searching for None returns an empty list."""
574 self.assertEqual([], self.index.get_topics(None))
575
576 def test_get_topics_no_topic(self):
577 self.assertEqual([], self.index.get_topics('nothing by this name'))
578
579 def test_prefix(self):
580 self.assertEqual('configuration/', self.index.prefix)
581
582 def test_get_topic_with_prefix(self):
583 topics = self.index.get_topics('configuration/default_format')
584 self.assertLength(1, topics)
585 opt = topics[0]
586 self.assertIsInstance(opt, config.Option)
587 self.assertEquals('default_format', opt.name)
588
589
564class TestCommandIndex(TestHelp):590class TestCommandIndex(TestHelp):
565 """Tests for the HelpCommandIndex class."""591 """Tests for the HelpCommandIndex class."""
566592
@@ -603,16 +629,19 @@
603 def test_default_search_path(self):629 def test_default_search_path(self):
604 """The default search path should include internal indexs."""630 """The default search path should include internal indexs."""
605 indices = help.HelpIndices()631 indices = help.HelpIndices()
606 self.assertEqual(3, len(indices.search_path))632 self.assertEqual(4, len(indices.search_path))
607 # help topics should be searched in first.633 # help topics should be searched in first.
608 self.assertIsInstance(indices.search_path[0],634 self.assertIsInstance(indices.search_path[0],
609 help_topics.HelpTopicIndex)635 help_topics.HelpTopicIndex)
610 # with commands being search second.636 # with commands being search second.
611 self.assertIsInstance(indices.search_path[1],637 self.assertIsInstance(indices.search_path[1],
612 commands.HelpCommandIndex)638 commands.HelpCommandIndex)
613 # and plugins are a third index.639 # plugins are a third index.
614 self.assertIsInstance(indices.search_path[2],640 self.assertIsInstance(indices.search_path[2],
615 plugin.PluginsHelpIndex)641 plugin.PluginsHelpIndex)
642 # config options are a fourth index
643 self.assertIsInstance(indices.search_path[3],
644 help_topics.ConfigOptionHelpIndex)
616645
617 def test_search_for_unknown_topic_raises(self):646 def test_search_for_unknown_topic_raises(self):
618 """Searching for an unknown topic should raise NoHelpTopic."""647 """Searching for an unknown topic should raise NoHelpTopic."""
619648
=== modified file 'bzrlib/tests/test_plugins.py'
--- bzrlib/tests/test_plugins.py 2011-05-16 13:49:58 +0000
+++ bzrlib/tests/test_plugins.py 2011-08-16 07:35:26 +0000
@@ -615,15 +615,16 @@
615 def test_get_help_text_with_additional_see_also(self):615 def test_get_help_text_with_additional_see_also(self):
616 mod = FakeModule('two lines of help\nand more', 'demo')616 mod = FakeModule('two lines of help\nand more', 'demo')
617 topic = plugin.ModuleHelpTopic(mod)617 topic = plugin.ModuleHelpTopic(mod)
618 self.assertEqual("two lines of help\nand more\nSee also: bar, foo\n",618 self.assertEqual("two lines of help\nand more\n\n:See also: bar, foo\n",
619 topic.get_help_text(['foo', 'bar']))619 topic.get_help_text(['foo', 'bar']))
620620
621 def test_get_help_topic(self):621 def test_get_help_topic(self):
622 """The help topic for a plugin is its module name."""622 """The help topic for a plugin is its module name."""
623 mod = FakeModule('two lines of help\nand more', 'bzrlib.plugins.demo')623 mod = FakeModule('two lines of help\nand more', 'bzrlib.plugins.demo')
624 topic = plugin.ModuleHelpTopic(mod)624 topic = plugin.ModuleHelpTopic(mod)
625 self.assertEqual('demo', topic.get_help_topic())625 self.assertEqual('demo', topic.get_help_topic())
626 mod = FakeModule('two lines of help\nand more', 'bzrlib.plugins.foo_bar')626 mod = FakeModule('two lines of help\nand more',
627 'bzrlib.plugins.foo_bar')
627 topic = plugin.ModuleHelpTopic(mod)628 topic = plugin.ModuleHelpTopic(mod)
628 self.assertEqual('foo_bar', topic.get_help_topic())629 self.assertEqual('foo_bar', topic.get_help_topic())
629630
630631
=== modified file 'doc/en/release-notes/bzr-2.5.txt'
--- doc/en/release-notes/bzr-2.5.txt 2011-08-15 13:49:38 +0000
+++ doc/en/release-notes/bzr-2.5.txt 2011-08-16 07:35:26 +0000
@@ -69,6 +69,9 @@
69 while --match-message, --match-author, --match-committer and69 while --match-message, --match-author, --match-committer and
70 --match-bugs match each of those fields.70 --match-bugs match each of those fields.
7171
72* ``bzr help configuration/<option>`` display the help for ``option`` for
73 all registered configuration options. (Vincent Ladeuil, #747050)
74
72* Relative local paths can now be specified in URL syntax by using the75* Relative local paths can now be specified in URL syntax by using the
73 "file:" prefix. (Jelmer Vernooij)76 "file:" prefix. (Jelmer Vernooij)
7477