From 47999e90554640bdfd884738bef1337fae1ff488 Mon Sep 17 00:00:00 2001 From: Dan Allen Date: Tue, 10 Oct 2023 00:29:12 -0600 Subject: [PATCH] resolves #566 add CLI option to specify a config file containing API options --- CHANGELOG.adoc | 1 + lib/asciidoctor/cli/invoker.rb | 21 +++++++++++++++++++++ lib/asciidoctor/cli/options.rb | 4 ++++ test/fixtures/config.yml | 3 +++ test/invoker_test.rb | 14 ++++++++++++++ 5 files changed, 43 insertions(+) create mode 100644 test/fixtures/config.yml diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 414322b45e..c77a70022a 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -35,6 +35,7 @@ Enhancements:: * Honor `level` and `formatter` keyword arguments passed to Logger constructor (#4250) * Set logdev to $stderr if no arguments are passed to Logger constructor (#4250) * Add support for skipping TOML front matter (Hugo) when `skip-front-matter` attribute is set (#4300) (*@abhinav*) + * Add `-c, --config-file` option to CLI to specify a config file containing API options (#566) Compliance:: diff --git a/lib/asciidoctor/cli/invoker.rb b/lib/asciidoctor/cli/invoker.rb index de16f4fd66..ec3dd6a5f7 100644 --- a/lib/asciidoctor/cli/invoker.rb +++ b/lib/asciidoctor/cli/invoker.rb @@ -46,6 +46,27 @@ def invoke! # NOTE in Ruby 2.7, RubyGems sets SOURCE_DATE_EPOCH if it's not set ::ENV.delete 'SOURCE_DATE_EPOCH' if (::ENV.key? 'IGNORE_SOURCE_DATE_EPOCH') && (::Gem.respond_to? :source_date_epoch) + if (config_file = @options[:config_file]) + require 'yaml' + if ::Hash === (config_data = ::YAML.load_file config_file) + if ::Hash === (nested_config_data = config_data['asciidoc'] || config_data[:asciidoc]) + config_data = nested_config_data + end + config_data.each do |opt_name, opt_val| + case (opt_name = opt_name.to_sym) + when :attributes + if ::Hash === opt_val + opt_val.each_with_object(@options[:attributes] ||= {}) {|(n, v), accum| accum[n] = v } + end + when :input_file, :output_file, :source_dir, :destination_dir + # ignore + else + @options[opt_name] = opt_val + end + end + end + end + @options.map do |key, val| case key when :input_files diff --git a/lib/asciidoctor/cli/options.rb b/lib/asciidoctor/cli/options.rb index b6476da2ed..fbc822f6db 100644 --- a/lib/asciidoctor/cli/options.rb +++ b/lib/asciidoctor/cli/options.rb @@ -9,6 +9,7 @@ module Cli class Options < ::Hash def initialize options = {} self[:attributes] = options[:attributes] || {} + self[:config_file] = options[:config_file] self[:input_files] = options[:input_files] self[:output_file] = options[:output_file] self[:safe] = options[:safe] || SafeMode::UNSAFE @@ -99,6 +100,9 @@ def parse! args name, _, val = attr.partition '=' self[:attributes][name] = val end + opts.on '-c', '--config-file FILE', 'a YAML file that contains API options defined as key-value pairs' do |config_file| + self[:config_file] = config_file + end opts.on '-T', '--template-dir DIR', 'a directory containing custom converter templates that override the built-in converter (requires tilt gem)', 'may be specified multiple times' do |template_dir| if self[:template_dirs].nil? diff --git a/test/fixtures/config.yml b/test/fixtures/config.yml new file mode 100644 index 0000000000..4b25024fbf --- /dev/null +++ b/test/fixtures/config.yml @@ -0,0 +1,3 @@ +asciidoc: + attributes: + toc: '' diff --git a/test/invoker_test.rb b/test/invoker_test.rb index a5e960a7b6..9aec13a9cb 100644 --- a/test/invoker_test.rb +++ b/test/invoker_test.rb @@ -210,6 +210,20 @@ assert_equal 'asciidoctor: INFO: possible invalid reference: install', output.chomp end + test 'should allow API options to be passed from config file' do + input_path = fixture_path 'sample.adoc' + config_path = fixture_path 'config.yml' + output = run_command(asciidoctor_cmd, '-c', config_path, '-o', '-', input_path) {|out| out.read } + assert_includes output, '
' + end + + test 'should merge attributes from config file with attributes passed as CLI options' do + input_path = fixture_path 'sample.adoc' + config_path = fixture_path 'config.yml' + output = run_command(asciidoctor_cmd, '-c', config_path, '-a', 'toc-class=interactive-toc', '-o', '-', input_path) {|out| out.read } + assert_includes output, '
' + end + test 'should not log when --log-level and -q are both specified' do input = <<~'EOS' skip to <>