require 'arli/configuration' require 'colored2' require 'optionparser' module Arli module CLI class Parser < ::OptionParser attr_accessor :output_lines, :command, :config def initialize(config: Arli.config, command: nil) super(nil, 22) self.config = config self.command = command self.output_lines = ::Array.new end def sep(text = nil) separator text || '' end def option_install option_lib_home option_if_exists end def option_bundle option_lib_home option_arlifile_path option_arlifile_lock_format option_if_exists end def option_arlifile_path on('-a', '--arli-path PATH', 'An alternate folder with the ' + 'Arlifile'.green + ' file.', "Defaults to the current directory.\n\n") do |v| config.arlifile.path = v end end SUPPORTED_FORMATS = %w[cmake text json yaml] def option_arlifile_lock_format on('-f', '--format FMT', "Arli writes an #{'Arlifile.lock'.green} with resolved info.", "The default format is #{'text'.bold.yellow}. Use -f to set it", "to one of: #{SUPPORTED_FORMATS.join(', ').bold.yellow}\n\n") do |v| if SUPPORTED_FORMATS.include?(v.downcase) config.arlifile.lock_format = v.downcase.to_sym else raise ::OptionParser::InvalidOption, "#{v.yellow} is not a supported lock file format" end end end def option_lib_home on('-l', '--lib-path PATH', 'Destination: typically your Arduino libraries folder', "Defaults to #{'~/Documents/Arduino/Libraries'.green}\n\n") do |v| config.libraries.path = v end end def option_search on('-d', '--database URL', 'a JSON(.gz) file path or a URL of the library database.', 'Defaults to the Arduino-maintained database.' + "\n\n") do |v| config.database.path = v end on('-m', '--max NUMBER', 'if provided, limits the result set using the ', 'total number of the unique library name matches.', 'Default is 0, which means no limit.' + "\n\n") do |v| config.search.results.limit = v.to_i if v end formats = Arli::Library::MultiVersion.format_methods on('-f', '--format FMT', "Optional format of the search results.", "The default is #{'short'.bold.yellow}. Available ", "formats: #{formats.join(', ').bold.yellow}\n\n") do |v| if formats.include?(v.downcase.to_sym) config.search.results.output_format = v.downcase.to_sym else raise ::OptionParser::InvalidOption, "#{v.yellow} is not a supported search result format" end end option_search_attributes end def option_generate on('-w', '--workspace DIR', 'a top-level folder under which the project will be created', 'Default is the current folder.' + "\n\n") do |v| config.generate.workspace = v end # on('-L', '--libs "LIBS"', # 'Comma separated list of library names, or name ', # 'substrings, to be searched for and added to the ', # 'initial Arlifile. Multiple matches are added anyway', # 'while no matches are skipped' + "\n\n") do |v| # config.generate.libs = v.split(',') # end option_if_exists('project') end def option_if_exists(what = 'library') on('-e', '--if-exists ACTION', "If a #{what} folder already exists, by default", 'it will be overwritten or updated if possible.', 'Alternatively you can either ' + 'abort'.bold.blue + ' or ' + 'backup'.bold.blue ) do |v| if v == 'abort' config.if_exists.abort = true config.if_exists.overwrite = false elsif v == 'backup' config.if_exists.backup = true end end sep ' ' end def option_help(commands: false, command_name: nil) common_help_options on('-h', '--help', 'prints this help') do ::Arli.config.help = true command_hash = output_command_description(command_name) output_examples(command_hash[:examples]) if command_hash && command_hash[:examples] output_command_help if commands output_help output_command_aliases(command_name) if command_name print_version_copyright end end def option_search_attributes on('-A', '--print-attrs', 'prints full list of available library', 'attributes that can be used in search strings.', ' ') do ::Arli.config.help = true output '' header('Arduino Library Attributes:') output " • " + Arduino::Library::Types::LIBRARY_PROPERTIES.keys.join("\n • ") + "\n\n" end end def header(string) output "#{string.bold.magenta}:" output end def output_examples(examples) header 'Examples' indent = ' ' examples.each do |example| output output indent + '# ' + example[:desc] output indent + example[:cmd].green output '' end end def option_help_with_subtext option_help end def output_help output self.to_s end def output_command_help output command_help end def command_help header 'Available Commands' subtext = '' factory.command_parsers.each_pair do |command, config| subtext << %Q/#{sprintf(' %-12s', command.to_s).green} — #{sprintf('%s', config[:sentence]).blue}\n/ end subtext << <<-EOS See #{Arli::Configuration::ARLI_COMMAND.blue + ' command '.green + '--help'.yellow} for more information on a specific command. EOS subtext end def output(value = nil) self.output_lines << value if value self.output_lines end def print puts output.join("\n") unless output.empty? end def factory Arli::CLI::ParserFactory end def common_help_options on('-C', '--no-color', 'Disable any color output.') do |*| Colored2.disable! # if $stdout.tty? config.no_color = true end on('-D', '--debug', 'Print debugging info.') do |v| config.debug = true end on('-t', '--trace', 'Print exception stack traces.') do |v| config.trace = v end on('-v', '--verbose', 'Print more information.') do |v| config.verbose = true end on('-q', '--quiet', 'Print less information.') do |v| config.quiet = true end on('-V', '--version', 'Print current version and exit') do |v| print_version_copyright Arli.config.help = true end end def print_version_copyright output << Arli::Configuration::ARLI_COMMAND.bold.yellow + ' (' + Arli::VERSION.bold.green + ')' + ' © 2017 Konstantin Gredeskoul, MIT License.'.dark unless Arli.config.quiet end def indent ' ' end def output_command_description(command_name) command_hash = factory.command_parsers[command_name] if command_hash if command_hash.description header 'Description' if command_hash.sentence output indent + command_hash.sentence.bold.blue output '' end text = Array(command_hash[:description]).flatten.join(' ') output text.reformat_wrapped(width = 70, indent_with = 4).yellow.dark end end command_hash end private def output_command_aliases(command_name) command_aliases = factory.command_aliases(command_name) || [] unless command_aliases.empty? header 'Aliases' output indent + command_aliases.join(', ').bold.blue output << '' end end end end end