1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
|
require_relative '../../puppet/face'
require_relative '../../puppet/application/face_base'
require_relative '../../puppet/util/constant_inflector'
require 'pathname'
require 'erb'
Puppet::Face.define(:help, '0.0.1') do
copyright "Puppet Inc.", 2011
license _("Apache 2 license; see COPYING")
summary _("Display Puppet help.")
action(:help) do
summary _("Display help about Puppet subcommands and their actions.")
arguments _("[<subcommand>] [<action>]")
returns _("Short help text for the specified subcommand or action.")
examples _(<<-'EOT')
Get help for an action:
$ puppet help
EOT
option "--version " + _("VERSION") do
summary _("The version of the subcommand for which to show help.")
end
option "--ronn" do
summary _("Whether to render the help text in ronn format.")
default_to { false }
end
default
when_invoked do |*args|
options = args.pop
unless options[:ronn]
if default_case?(args) || help_for_help?(args)
return erb('global.erb').result(binding)
end
end
if args.length > 2
#TRANSLATORS 'puppet help' is a command line and should not be translated
raise ArgumentError, _("The 'puppet help' command takes two (optional) arguments: a subcommand and an action")
end
version = :current
if options.has_key? :version
if options[:version].to_s !~ /^current$/i
version = options[:version]
else
if args.length == 0
#TRANSLATORS '--version' is a command line option and should not be translated
raise ArgumentError, _("Supplying a '--version' only makes sense when a Faces subcommand is given")
end
end
end
facename, actionname = args
if legacy_applications.include? facename
if actionname
raise ArgumentError, _("The legacy subcommand '%{sub_command}' does not support supplying an action") % { sub_command: facename }
end
# legacy apps already emit ronn output
return render_application_help(facename)
else
if options[:ronn]
# Calling `puppet help <app> --ronn` normally calls this action with
# <app> as the first argument in the `args` array. However, if <app>
# happens to match the name of an action, like `puppet help help
# --ronn`, then face_base "eats" the argument and `args` will be
# empty. Rather than force users to type `puppet help help help
# --ronn`, default the facename to `:help`
render_face_man(facename || :help)
else
render_face_help(facename, actionname, version)
end
end
end
end
def default_case?(args)
args.empty?
end
def help_for_help?(args)
args.length == 1 && args.first == 'help'
end
def render_face_man(facename)
# set 'face' as it's used in the erb processing.
face = Puppet::Face[facename.to_sym, :current]
# avoid unused variable warning
_face = face
erb('man.erb').result(binding)
end
def render_application_help(applicationname)
return Puppet::Application[applicationname].help
rescue StandardError, LoadError => detail
message = []
message << _('Could not load help for the application %{application_name}.') % { application_name: applicationname }
message << _('Please check the error logs for more information.')
message << ''
message << _('Detail: "%{detail}"') % { detail: detail.message }
fail ArgumentError, message.join("\n"), detail.backtrace
end
def render_face_help(facename, actionname, version)
face, action = load_face_help(facename, actionname, version)
return template_for(face, action).result(binding)
rescue StandardError, LoadError => detail
message = []
message << _('Could not load help for the face %{face_name}.') % { face_name: facename }
message << _('Please check the error logs for more information.')
message << ''
message << _('Detail: "%{detail}"') % { detail: detail.message }
fail ArgumentError, message.join("\n"), detail.backtrace
end
def load_face_help(facename, actionname, version)
face = Puppet::Face[facename.to_sym, version]
if actionname
action = face.get_action(actionname.to_sym)
if ! action
fail ArgumentError, _("Unable to load action %{actionname} from %{face}") % { actionname: actionname, face: face }
end
end
[face, action]
end
def template_for(face, action)
if action.nil?
erb('face.erb')
else
erb('action.erb')
end
end
def erb(name)
template = (Pathname(__FILE__).dirname + "help" + name)
erb = Puppet::Util.create_erb(template.read)
erb.filename = template.to_s
return erb
end
# Return a list of applications that are not simply just stubs for Faces.
def legacy_applications
Puppet::Application.available_application_names.reject do |appname|
(is_face_app?(appname)) or (exclude_from_docs?(appname))
end.sort
end
# Return a list of all applications (both legacy and Face applications), along with a summary
# of their functionality.
# @return [Array] An Array of Arrays. The outer array contains one entry per application; each
# element in the outer array is a pair whose first element is a String containing the application
# name, and whose second element is a String containing the summary for that application.
def all_application_summaries()
available_application_names_special_sort().inject([]) do |result, appname|
next result if exclude_from_docs?(appname)
if (appname == COMMON || appname == SPECIALIZED || appname == BLANK)
result << appname
elsif (is_face_app?(appname))
begin
face = Puppet::Face[appname, :current]
# Add deprecation message to summary if the face is deprecated
summary = face.deprecated? ? face.summary + ' ' + _("(Deprecated)") : face.summary
result << [appname, summary, ' ']
rescue StandardError, LoadError
error_message = _("!%{sub_command}! Subcommand unavailable due to error.") % { sub_command: appname }
error_message += ' ' + _("Check error logs.")
result << [ error_message, '', ' ' ]
end
else
begin
summary = Puppet::Application[appname].summary
if summary.empty?
summary = horribly_extract_summary_from(appname)
end
result << [appname, summary, ' ']
rescue StandardError, LoadError
error_message = _("!%{sub_command}! Subcommand unavailable due to error.") % { sub_command: appname }
error_message += ' ' + _("Check error logs.")
result << [ error_message, '', ' ' ]
end
end
end
end
COMMON = 'Common:'.freeze
SPECIALIZED = 'Specialized:'.freeze
BLANK = "\n".freeze
def available_application_names_special_sort()
full_list = Puppet::Application.available_application_names
a_list = full_list & %w{apply agent config help lookup module resource}
a_list = a_list.sort
also_ran = full_list - a_list
also_ran = also_ran.sort
[[COMMON], a_list, [BLANK], [SPECIALIZED], also_ran].flatten(1)
end
def horribly_extract_summary_from(appname)
help = Puppet::Application[appname].help.split("\n")
# Now we find the line with our summary, extract it, and return it. This
# depends on the implementation coincidence of how our pages are
# formatted. If we can't match the pattern we expect we return the empty
# string to ensure we don't blow up in the summary. --daniel 2011-04-11
while line = help.shift do #rubocop:disable Lint/AssignmentInCondition
md = /^puppet-#{appname}\([^\)]+\) -- (.*)$/.match(line)
if md
return md[1]
end
end
return ''
end
# This should absolutely be a private method, but for some reason it appears
# that you can't use the 'private' keyword inside of a Face definition.
# See #14205.
#private :horribly_extract_summary_from
def exclude_from_docs?(appname)
%w{face_base indirection_base report status}.include? appname
end
# This should absolutely be a private method, but for some reason it appears
# that you can't use the 'private' keyword inside of a Face definition.
# See #14205.
#private :exclude_from_docs?
def is_face_app?(appname)
clazz = Puppet::Application.find(appname)
clazz.ancestors.include?(Puppet::Application::FaceBase)
end
# This should probably be a private method, but for some reason it appears
# that you can't use the 'private' keyword inside of a Face definition.
# See #14205.
#private :is_face_app?
end
|