1# -*- coding: utf-8 -*- #
2# Copyright 2013 Google LLC. All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#    http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16"""A calliope command that prints help for another calliope command."""
17
18from __future__ import absolute_import
19from __future__ import division
20from __future__ import unicode_literals
21
22import argparse
23
24from googlecloudsdk.calliope import base
25from googlecloudsdk.command_lib.help_search import search
26from googlecloudsdk.command_lib.help_search import search_util
27from googlecloudsdk.core import log
28
29
30_DEFAULT_LIMIT = 5
31
32
33class Help(base.ListCommand):
34  """Search gcloud help text.
35
36  If a full gcloud command is specified after the ``help'' operand, {command}
37  prints a detailed help message for that command.
38
39  Otherwise, {command} runs a search for all commands with help text matching
40  the given argument or arguments. It prints the command name and a summary of
41  the help text for any command that it finds as a result.
42
43  To run a search directly, you can use remainder arguments, following a `--`.
44
45  By default, command results are displayed in a table that shows the name
46  of the command and snippets of the help text that relate to your search terms.
47
48  By default, search results are sorted from most to least relevant by default,
49  using a localized rating based on several heuristics. These heuristics may
50  change in future runs of this command.
51
52  ## EXAMPLES
53
54  To get the help for the command `gcloud projects describe`, run:
55
56    $ {command} projects describe
57
58  To search for all commands whose help text contains the word `project`, run:
59
60    $ {command} -- project
61
62  To search for commands whose help text contains the word `project` and the
63  string `--foo`, run:
64
65    $ {command} -- project --foo
66
67  To search and receive more than the default limit of 5 search results, run:
68
69    $ {command} --limit=20 -- project
70
71  To search for a term and sort the results by a different characteristic, such
72  as command name, run:
73
74    $ {command} --sort-by=name -- project
75  """
76
77  category = base.SDK_TOOLS_CATEGORY
78
79  @staticmethod
80  def Args(parser):
81    parser.display_info.AddTransforms(search_util.GetTransforms())
82    parser.display_info.AddFormat("""
83        table[all-box,pager](
84            commandpath():label='COMMAND',
85            summary():wrap)
86        """)
87    base.URI_FLAG.RemoveFromParser(parser)
88    base.LIMIT_FLAG.SetDefault(parser, _DEFAULT_LIMIT)
89    base.SORT_BY_FLAG.SetDefault(parser, '~relevance')
90    parser.add_argument(
91        'command',
92        nargs='*',
93        help="""\
94Sequence of names representing a gcloud group or command name.
95
96If the arguments provide the name of a gcloud command, the full help
97text of that command will be displayed. Otherwise, all arguments will
98be considered search terms and used to search through all of gcloud's
99help text.
100""")
101
102    parser.add_argument(
103        'search_terms',
104        nargs=argparse.REMAINDER,
105        help="""\
106Search terms. The command will return a list of gcloud commands that are
107relevant to the searched term. If this argument is provided, the command
108will always return a list of search results rather than displaying help
109text of a single command.
110
111For example, to search for commands that relate to the term `project` or
112`folder`, run:
113
114  $ {command} -- project folder
115""")
116
117  def Run(self, args):
118    if not args.search_terms:
119      try:
120        # --document=style=help to signal the metrics.Help() 'help' label in
121        # actions.RenderDocumentAction().Action().
122        self.ExecuteCommandDoNotUse(args.command + ['--document=style=help'])
123        return None
124      except Exception:  # pylint: disable=broad-except
125        # In this case, we will treat the arguments as search terms.
126        pass
127
128    results = search.RunSearch(
129        args.command + (args.search_terms or []),
130        self._cli_power_users_only)
131
132    self._resources_found = len(results)
133    self._resources_displayed = min(len(results), args.limit)
134    return results
135
136  def Epilog(self, resources_were_displayed):
137    if not self._resources_found:
138      return
139    if resources_were_displayed:
140      log.status.Print(
141          'Listed {} of {} items.'.format(self._resources_displayed,
142                                          self._resources_found))
143    else:
144      log.status.Print('Listed 0 items.')
145