pandocomatic 1.1.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/pandocomatic/cli.rb +57 -5
- data/lib/pandocomatic/command/command.rb +3 -10
- data/lib/pandocomatic/command/convert_dir_command.rb +4 -1
- data/lib/pandocomatic/command/convert_file_command.rb +28 -12
- data/lib/pandocomatic/command/convert_file_multiple_command.rb +6 -4
- data/lib/pandocomatic/command/convert_list_command.rb +4 -2
- data/lib/pandocomatic/command/copy_file_command.rb +4 -1
- data/lib/pandocomatic/command/create_link_command.rb +4 -1
- data/lib/pandocomatic/configuration.rb +124 -12
- data/lib/pandocomatic/default_configuration.yaml +1 -0
- data/lib/pandocomatic/error/pandocomatic_error.rb +1 -1
- data/lib/pandocomatic/input.rb +1 -3
- data/lib/pandocomatic/pandoc_metadata.rb +18 -9
- data/lib/pandocomatic/pandocomatic.rb +109 -5
- data/lib/pandocomatic/pandocomatic_yaml.rb +1 -1
- data/lib/pandocomatic/printer/command_printer.rb +1 -1
- data/lib/pandocomatic/printer/configuration_errors_printer.rb +8 -2
- data/lib/pandocomatic/printer/error_printer.rb +3 -2
- data/lib/pandocomatic/printer/finish_printer.rb +1 -1
- data/lib/pandocomatic/printer/help_printer.rb +1 -1
- data/lib/pandocomatic/printer/printer.rb +1 -0
- data/lib/pandocomatic/printer/summary_printer.rb +1 -1
- data/lib/pandocomatic/printer/unknown_error_printer.rb +39 -0
- data/lib/pandocomatic/printer/version_printer.rb +1 -1
- data/lib/pandocomatic/printer/views/cli_error.txt +3 -0
- data/lib/pandocomatic/printer/views/help.txt +26 -9
- data/lib/pandocomatic/printer/views/pandoc_metadata_error.txt +1 -1
- data/lib/pandocomatic/printer/views/unknown_error.txt +2 -0
- data/lib/pandocomatic/printer/warning_printer.rb +3 -2
- data/lib/pandocomatic/processors/fileinfo_preprocessor.rb +17 -12
- data/lib/pandocomatic/processors/metadata_preprocessor.rb +7 -5
- data/lib/pandocomatic/template.rb +1 -1
- data/lib/pandocomatic/version.rb +2 -2
- metadata +50 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e382c7e0385533687f62deba0a3a1e468b5a1e0c5157b4df5ece4e8c55ac514
|
4
|
+
data.tar.gz: c1d24a4b5f28cf0c902a99fc0f68f598e08fdbb15f06bf4ea9981f6b57829a05
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a7527caccb62a545f59557f6dbb0e2e37edab002530069b8b8cec4fb9d16bbc8ec85d916be1ec6c74f0cfdeedaa62de8c0579ecebc268a9c950828bbd4df4460
|
7
|
+
data.tar.gz: 34b755458f0a7346dd53040c870358e4feac2b3ea93ff64341858f4d2a7820f77ac0227c39123ba1cdb71baea3d5848ef054d5674404b9b6aae8c029c6d1414e
|
data/lib/pandocomatic/cli.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright 2017-
|
4
|
+
# Copyright 2017-2024, Huub de Beer <huub@heerdebeer.org>
|
5
5
|
#
|
6
6
|
# This file is part of pandocomatic.
|
7
7
|
#
|
@@ -32,11 +32,14 @@ module Pandocomatic
|
|
32
32
|
# Parse the arguments, returns a triplet with the global options, an
|
33
33
|
# optional subcommand, and the (optional) options for that subcommand.
|
34
34
|
#
|
35
|
+
# As a side effect, this method will create and install a logger for
|
36
|
+
# Pandocomatic::LOG.
|
37
|
+
#
|
35
38
|
# @param args [String, Array] A command-line invocation string or a list of strings like ARGV
|
36
39
|
#
|
37
40
|
# @return [Configuration] The configuration for running pandocomatic given
|
38
41
|
# the command-line options.
|
39
|
-
def self.parse(args)
|
42
|
+
def self.parse!(args)
|
40
43
|
args = args.split if args.is_a? String
|
41
44
|
|
42
45
|
begin
|
@@ -56,8 +59,12 @@ module Pandocomatic
|
|
56
59
|
# General options
|
57
60
|
opt :dry_run, 'Do a dry run', short: '-y'
|
58
61
|
opt :verbose, 'Run verbosely', short: '-V'
|
59
|
-
opt :debug, 'Debug mode, shows pandoc invocations', short: '-b'
|
60
62
|
opt :modified_only, 'Modified files only', short: '-m'
|
63
|
+
opt :enable, 'Enable feature', short: '-e', multi: true, type: String
|
64
|
+
|
65
|
+
# Logging
|
66
|
+
opt :log, 'Log to file', short: '-l', type: String, default: 'pandocomatic.log'
|
67
|
+
opt :log_level, 'Log level', type: String, default: 'INFO'
|
61
68
|
|
62
69
|
# Configuration of the converter
|
63
70
|
opt :data_dir, 'Data dir', short: '-d', type: String
|
@@ -75,19 +82,33 @@ module Pandocomatic
|
|
75
82
|
end
|
76
83
|
|
77
84
|
# All options should be parsed according to the specification given in the parser
|
85
|
+
# parser#parse removes arguments from args during parsing. Keep a copy for error reporting.
|
86
|
+
given_arguments = args.dup
|
87
|
+
|
78
88
|
begin
|
79
89
|
options = parser.parse args
|
80
90
|
rescue Optimist::CommandlineError => e
|
81
|
-
raise CLIError.new(:problematic_invocation, e,
|
91
|
+
raise CLIError.new(:problematic_invocation, e, given_arguments)
|
82
92
|
end
|
83
93
|
|
94
|
+
if options[:log_given]
|
95
|
+
log_file = options[:log]
|
96
|
+
log_level = options[:log_level]
|
97
|
+
end
|
98
|
+
|
99
|
+
Pandocomatic::LOG.install_file_logger(log_file, log_level)
|
100
|
+
|
84
101
|
options = use_custom_version options
|
85
102
|
options = use_custom_help options
|
86
103
|
|
87
104
|
if options_need_to_be_validated? options
|
105
|
+
Pandocomatic::LOG.debug 'Validating command-line arguments:'
|
106
|
+
|
88
107
|
# if no input option is specified, all items following the last option
|
89
108
|
# are treated as input files.
|
90
109
|
if !(options[:input_given])
|
110
|
+
Pandocomatic::LOG.debug '✓ Option \'--input\' not used: ' \
|
111
|
+
'treat all arguments after last option as input files or directories.'
|
91
112
|
options[:input] = args
|
92
113
|
options[:input_given] = true
|
93
114
|
elsif !args.empty?
|
@@ -100,6 +121,12 @@ module Pandocomatic
|
|
100
121
|
# Support multiple input files for conversion
|
101
122
|
multiple_inputs = options[:input].size > 1
|
102
123
|
|
124
|
+
if multiple_inputs
|
125
|
+
Pandocomatic::LOG.debug '✓ Convert multiple input files or directories.'
|
126
|
+
else
|
127
|
+
Pandocomatic::LOG.debug '✓ Convert single input file or directory.'
|
128
|
+
end
|
129
|
+
|
103
130
|
# The input files or directories should exist
|
104
131
|
input = options[:input].map do |input_file|
|
105
132
|
raise CLIError.new(:input_does_not_exist, nil, input_file) unless File.exist? input_file
|
@@ -113,12 +140,14 @@ module Pandocomatic
|
|
113
140
|
|
114
141
|
File.absolute_path input_file
|
115
142
|
end
|
143
|
+
Pandocomatic::LOG.debug '✓ Input files and directories exist.'
|
116
144
|
|
117
145
|
# You cannot use the --stdout option while converting directories
|
118
146
|
if options[:stdout_given] && File.directory?(input.first)
|
119
147
|
options[:stdout] = false
|
120
148
|
raise CLIError, :cannot_use_stdout_with_directory
|
121
149
|
end
|
150
|
+
Pandocomatic::LOG.debug '✓ Write output to STDOUT.' if options[:stdout_given]
|
122
151
|
|
123
152
|
if options[:output_given]
|
124
153
|
# You cannot use --stdout with --output
|
@@ -126,19 +155,23 @@ module Pandocomatic
|
|
126
155
|
options[:stdout] = false
|
127
156
|
raise CLIError, :cannot_use_both_output_and_stdout
|
128
157
|
else
|
158
|
+
Pandocomatic::LOG.debug "✓ Write output to '#{options[:output]}'."
|
129
159
|
output = File.absolute_path options[:output]
|
130
160
|
# Input and output should be both files or directories
|
131
161
|
match_file_types input.first, output
|
162
|
+
Pandocomatic::LOG.debug '✓ Input and outputs types match.'
|
132
163
|
|
133
164
|
# The output, if it already exist, should be writable
|
134
165
|
unless (!File.exist? output) || File.writable?(output)
|
135
166
|
raise CLIError.new(:output_is_not_writable, nil,
|
136
167
|
output)
|
137
168
|
end
|
169
|
+
Pandocomatic::LOG.debug '✓ Existing output is writable.' if File.exist? output
|
138
170
|
end
|
139
171
|
elsif !multiple_inputs && File.directory?(input.first)
|
140
172
|
raise CLIError, :no_output_given
|
141
173
|
end
|
174
|
+
|
142
175
|
# If the input is a directory, an output directory should be
|
143
176
|
# specified as well. If the input is a file, the output could be
|
144
177
|
# specified in the input file, or STDOUT could be used.
|
@@ -154,6 +187,7 @@ module Pandocomatic
|
|
154
187
|
raise CLIError.new(:data_dir_is_not_readable, nil, data_dir) unless File.readable? data_dir
|
155
188
|
raise CLIError.new(:data_dir_is_not_a_directory, nil, data_dir) unless File.directory? data_dir
|
156
189
|
end
|
190
|
+
Pandocomatic::LOG.debug "✓ Can read data directory '#{options[:data_dir]}'." if options[:data_dir_given]
|
157
191
|
|
158
192
|
# Config file, if specified, should be an existing and readable file
|
159
193
|
if options[:config_given]
|
@@ -163,10 +197,28 @@ module Pandocomatic
|
|
163
197
|
raise CLIError.new(:config_file_is_not_readable, nil, config) unless File.readable? config
|
164
198
|
raise CLIError.new(:config_file_is_not_a_file, nil, config) unless File.file? config
|
165
199
|
end
|
200
|
+
Pandocomatic::LOG.debug "✓ Can read configuration file '#{options[:config]}'." if options[:config_given]
|
201
|
+
|
202
|
+
if options[:enable_given]
|
203
|
+
Pandocomatic::LOG.info '- Checking feature toggles:'
|
166
204
|
|
205
|
+
features = []
|
206
|
+
|
207
|
+
options[:enable].each do |feature_string|
|
208
|
+
feature = feature_string.downcase.sub('-', '_').to_sym
|
209
|
+
unless Pandocomatic::FEATURES.include? feature
|
210
|
+
raise CLIError.new(:feature_toggle_does_not_exist, nil, feature_string)
|
211
|
+
end
|
212
|
+
|
213
|
+
Pandocomatic::LOG.info " ✓ Enabling feature '#{feature}'."
|
214
|
+
features << feature
|
215
|
+
end
|
216
|
+
|
217
|
+
options[:enable] = features
|
218
|
+
end
|
167
219
|
end
|
168
220
|
|
169
|
-
Configuration.new
|
221
|
+
Configuration.new(options, input)
|
170
222
|
end
|
171
223
|
|
172
224
|
# rubocop:enable Metrics
|
@@ -39,7 +39,6 @@ module Pandocomatic
|
|
39
39
|
@@total = 0
|
40
40
|
@@dry_run = false
|
41
41
|
@@quiet = false
|
42
|
-
@@debug = false
|
43
42
|
@@src_root = '.'
|
44
43
|
@@modified_only = false
|
45
44
|
|
@@ -57,7 +56,6 @@ module Pandocomatic
|
|
57
56
|
@@src_root = configuration.src_root
|
58
57
|
@@dry_run = configuration.dry_run?
|
59
58
|
@@quiet = configuration.quiet?
|
60
|
-
@@debug = configuration.debug?
|
61
59
|
@@modified_only = configuration.modified_only?
|
62
60
|
@@total = 0
|
63
61
|
end
|
@@ -83,13 +81,6 @@ module Pandocomatic
|
|
83
81
|
@@quiet
|
84
82
|
end
|
85
83
|
|
86
|
-
# Is this Command executed in debug mode?
|
87
|
-
#
|
88
|
-
# @return [Boolean]
|
89
|
-
def debug?
|
90
|
-
@@debug
|
91
|
-
end
|
92
|
-
|
93
84
|
# Is this Command only executed on modified files?
|
94
85
|
#
|
95
86
|
# @return [Boolean]
|
@@ -127,7 +118,9 @@ module Pandocomatic
|
|
127
118
|
# Execute this Command. A Command can be dry-run as well, in which it is
|
128
119
|
# not actually run.
|
129
120
|
def execute
|
130
|
-
CommandPrinter.new(self)
|
121
|
+
description = CommandPrinter.new(self)
|
122
|
+
Pandocomatic::LOG.info description
|
123
|
+
description.print unless quiet?
|
131
124
|
run if !dry_run? && runnable?
|
132
125
|
end
|
133
126
|
|
@@ -128,7 +128,10 @@ module Pandocomatic
|
|
128
128
|
|
129
129
|
# Run this command
|
130
130
|
def run
|
131
|
-
|
131
|
+
if create_directory?
|
132
|
+
Pandocomatic::LOG.info " Creating directory '#{@dst_dir}'"
|
133
|
+
Dir.mkdir @dst_dir
|
134
|
+
end
|
132
135
|
rescue SystemError => e
|
133
136
|
raise IOError.new(:error_creating_directory, e, @dst_dir)
|
134
137
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright 2017-
|
4
|
+
# Copyright 2017-2024, Huub de Beer <Huub@heerdebeer.org>
|
5
5
|
#
|
6
6
|
# This file is part of pandocomatic.
|
7
7
|
#
|
@@ -21,6 +21,7 @@
|
|
21
21
|
module Pandocomatic
|
22
22
|
require 'paru'
|
23
23
|
require 'shellwords'
|
24
|
+
require 'yaml'
|
24
25
|
|
25
26
|
require_relative 'command'
|
26
27
|
require_relative '../error/io_error'
|
@@ -100,8 +101,7 @@ module Pandocomatic
|
|
100
101
|
else
|
101
102
|
template_name
|
102
103
|
end
|
103
|
-
|
104
|
-
@metadata = PandocMetadata.load_file @src
|
104
|
+
@metadata = @config.get_metadata @src, @template_name
|
105
105
|
@dst = @config.set_destination @dst, @template_name, @metadata
|
106
106
|
|
107
107
|
@errors.push IOError.new(:file_does_not_exist, nil, @src) unless File.exist? @src
|
@@ -149,15 +149,27 @@ module Pandocomatic
|
|
149
149
|
template = Template.new INTERNAL_TEMPLATE
|
150
150
|
end
|
151
151
|
|
152
|
+
if template.name == INTERNAL_TEMPLATE
|
153
|
+
Pandocomatic::LOG.debug ' # Using internal template.'
|
154
|
+
else
|
155
|
+
Pandocomatic::LOG.debug " # Using template '#{template.name}'."
|
156
|
+
end
|
157
|
+
|
152
158
|
# Ignore the `--verbose` option, and warn about ignoring it
|
153
|
-
if pandoc_options.key?
|
159
|
+
if pandoc_options.key?('verbose') && !@config.feature_enabled?(:pandoc_verbose)
|
154
160
|
pandoc_options.delete 'verbose'
|
155
|
-
warn 'WARNING: Ignoring the pandoc option --verbose because it ' \
|
156
|
-
'might interfere with the working of pandocomatic.'
|
161
|
+
warn 'WARNING: Ignoring the pandoc option "--verbose" because it ' \
|
162
|
+
'might interfere with the working of pandocomatic. If you want to use ' \
|
163
|
+
'"--verbose" anyway, use pandocomatic\'s feature toggle ' \
|
164
|
+
'"--enable pandoc-verbose".'
|
157
165
|
end
|
158
166
|
|
159
167
|
template.merge! Template.new(INTERNAL_TEMPLATE, @metadata.pandocomatic) if @metadata.pandocomatic?
|
160
168
|
|
169
|
+
Pandocomatic::LOG.debug ' # Selected template mixed with internal template and pandocomatic metadata ' \
|
170
|
+
"gives final template:#{Pandocomatic::LOG.indent(YAML.dump(template.to_h).sub('---', ''),
|
171
|
+
34)}"
|
172
|
+
|
161
173
|
# Write out the results of the conversion process to file.
|
162
174
|
@dst = @metadata.pandoc_options['output'] if @dst.to_s.empty? && @metadata.pandoc_options.key?('output')
|
163
175
|
|
@@ -165,6 +177,7 @@ module Pandocomatic
|
|
165
177
|
setup template
|
166
178
|
|
167
179
|
# Read in the file to convert
|
180
|
+
Pandocomatic::LOG.debug " → Reading source file: '#{@src}'"
|
168
181
|
input = File.read @src
|
169
182
|
|
170
183
|
# Run the default preprocessors to mix-in information about the file
|
@@ -181,12 +194,13 @@ module Pandocomatic
|
|
181
194
|
|
182
195
|
begin
|
183
196
|
# Either output to file or to STDOUT.
|
184
|
-
|
185
197
|
if @config.stdout?
|
198
|
+
Pandocomatic::LOG.debug ' ← Writing output to STDOUT.'
|
186
199
|
puts output
|
187
200
|
@dst.close!
|
188
201
|
else
|
189
202
|
unless use_output_option @dst
|
203
|
+
Pandocomatic::LOG.debug " ← Writing output to '#{@dst}'."
|
190
204
|
File.open(@dst, 'w') do |file|
|
191
205
|
raise IOError.new(:file_is_not_a_file, nil, @dst) unless File.file? @dst
|
192
206
|
raise IOError.new(:file_is_not_writable, nil, @dst) unless File.writable? @dst
|
@@ -206,6 +220,7 @@ module Pandocomatic
|
|
206
220
|
def pandoc(input, options, src_dir)
|
207
221
|
absolute_dst = File.expand_path @dst
|
208
222
|
Dir.chdir(src_dir) do
|
223
|
+
Pandocomatic::LOG.debug " # Changing directory to '#{src_dir}'"
|
209
224
|
converter = Paru::Pandoc.new
|
210
225
|
options.each do |option, value|
|
211
226
|
# Options come from a YAML string. In YAML, properties without a value get value nil.
|
@@ -235,17 +250,16 @@ module Pandocomatic
|
|
235
250
|
(option == 'rename')
|
236
251
|
# don't let pandoc write the output to enable postprocessing
|
237
252
|
rescue StandardError
|
238
|
-
|
239
|
-
|
240
|
-
'is not recognized by paru. This option is skipped.'
|
241
|
-
end
|
253
|
+
Pandocomatic::LOG.warn "WARNING: The pandoc option '#{option}'"
|
254
|
+
" (with value '#{value}') is not recognized by paru. This option is skipped."
|
242
255
|
end
|
243
256
|
end
|
244
257
|
|
245
258
|
converter.send 'output', absolute_dst if use_output_option absolute_dst
|
246
259
|
|
247
260
|
begin
|
248
|
-
|
261
|
+
Pandocomatic::LOG.debug ' # Running pandoc'
|
262
|
+
Pandocomatic::LOG.debug " | #{Pandocomatic::LOG.indent(converter.to_command, 43)}"
|
249
263
|
converter << input
|
250
264
|
rescue Paru::Error => e
|
251
265
|
raise PandocError.new(:error_running_pandoc, e, input)
|
@@ -293,6 +307,7 @@ module Pandocomatic
|
|
293
307
|
def process(input, type, template)
|
294
308
|
if template.send "#{type}?"
|
295
309
|
processors = template.send type
|
310
|
+
Pandocomatic::LOG.debug " # Running #{type}:" unless processors.empty?
|
296
311
|
output = input
|
297
312
|
processors.each do |processor|
|
298
313
|
script = if Path.local_path? processor
|
@@ -313,6 +328,7 @@ module Pandocomatic
|
|
313
328
|
raise ProcessorError.new(:script_is_not_executable, nil, command) unless File.executable? command
|
314
329
|
|
315
330
|
begin
|
331
|
+
Pandocomatic::LOG.debug " | #{script}"
|
316
332
|
output = Processor.run(script, output)
|
317
333
|
rescue StandardError => e
|
318
334
|
ProcessorError.new(:error_processing_script, e, [script, @src])
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright 2017
|
4
|
+
# Copyright 2017—2024 Huub de Beer <Huub@heerdebeer.org>
|
5
5
|
#
|
6
6
|
# This file is part of pandocomatic.
|
7
7
|
#
|
@@ -49,11 +49,11 @@ module Pandocomatic
|
|
49
49
|
@config = config
|
50
50
|
@src = src
|
51
51
|
|
52
|
-
metadata =
|
52
|
+
metadata = @config.get_metadata @src
|
53
53
|
|
54
54
|
subcommands = []
|
55
55
|
|
56
|
-
if metadata
|
56
|
+
if metadata&.template?
|
57
57
|
# There are templates in this document's metadata, try to use
|
58
58
|
# those.
|
59
59
|
metadata.templates.each do |template_name|
|
@@ -99,7 +99,9 @@ module Pandocomatic
|
|
99
99
|
def execute
|
100
100
|
return if @subcommands.empty?
|
101
101
|
|
102
|
-
CommandPrinter.new(self)
|
102
|
+
description = CommandPrinter.new(self)
|
103
|
+
Pandocomatic::LOG.info description
|
104
|
+
description.print unless quiet? || (@subcommands.size == 1)
|
103
105
|
run if !dry_run? && runnable?
|
104
106
|
|
105
107
|
@subcommands.each(&:execute)
|
@@ -36,7 +36,7 @@ module Pandocomatic
|
|
36
36
|
|
37
37
|
# Create a new ConvertListCommand
|
38
38
|
def initialize
|
39
|
-
super
|
39
|
+
super
|
40
40
|
@subcommands = []
|
41
41
|
end
|
42
42
|
|
@@ -89,7 +89,9 @@ module Pandocomatic
|
|
89
89
|
def execute
|
90
90
|
return if @subcommands.empty?
|
91
91
|
|
92
|
-
CommandPrinter.new(self)
|
92
|
+
description = CommandPrinter.new(self)
|
93
|
+
Pandocomatic::LOG.info description
|
94
|
+
description.print unless quiet?
|
93
95
|
run if !dry_run? && runnable?
|
94
96
|
|
95
97
|
@subcommands.each(&:execute)
|
@@ -45,7 +45,10 @@ module Pandocomatic
|
|
45
45
|
|
46
46
|
# Run this CopyFileCommand
|
47
47
|
def run
|
48
|
-
|
48
|
+
if file_modified?(@src, @dst)
|
49
|
+
Pandocomatic::LOG.info "Copying '#{@src}' → '#{@dst}'"
|
50
|
+
FileUtils.cp(@src, @dst)
|
51
|
+
end
|
49
52
|
rescue StandardError => e
|
50
53
|
raise IOError.new(:unable_to_copy_file, e, [@src, @dst])
|
51
54
|
end
|
@@ -67,7 +67,10 @@ module Pandocomatic
|
|
67
67
|
|
68
68
|
# Run this CreateLinkCommand
|
69
69
|
def run
|
70
|
-
|
70
|
+
unless File.exist? @dst
|
71
|
+
File.symlink @dst_target, @dst
|
72
|
+
Pandocomatic::LOG.info "Creating symlink '#{@dst_target}' → '#{@dst}'"
|
73
|
+
end
|
71
74
|
rescue StandardError => e
|
72
75
|
raise IOError.new(:unable_to_create_symbolic_link, e, [@src, @dst])
|
73
76
|
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# rubocop:disable Metrics
|
3
4
|
#--
|
4
|
-
# Copyright 2014—
|
5
|
+
# Copyright 2014—2024 Huub de Beer <Huub@heerdebeer.org>
|
5
6
|
#
|
6
7
|
# This file is part of pandocomatic.
|
7
8
|
#
|
@@ -41,6 +42,7 @@ module Pandocomatic
|
|
41
42
|
# "unskip" option
|
42
43
|
DEFAULT_SETTINGS = {
|
43
44
|
'skip' => ['.*', 'pandocomatic.yaml'],
|
45
|
+
'extract-metadata-from' => [],
|
44
46
|
'recursive' => true,
|
45
47
|
'follow-links' => false,
|
46
48
|
'match-files' => 'first'
|
@@ -111,7 +113,71 @@ module Pandocomatic
|
|
111
113
|
'zimwiki' => 'zimwiki'
|
112
114
|
}.freeze
|
113
115
|
|
114
|
-
#
|
116
|
+
# Pandoc's mapping from file extensions to pandoc source format. Taken from
|
117
|
+
# https://github.com/jgm/pandoc/blob/main/src/Text/Pandoc/Format.hs
|
118
|
+
PANDOCS_EXTENSION_TO_FORMAT_MAPPING = {
|
119
|
+
'.Rmd' => 'markdown',
|
120
|
+
'.adoc' => 'asciidoc',
|
121
|
+
'.asciidoc' => 'asciidoc',
|
122
|
+
'.bib' => 'biblatex',
|
123
|
+
'.context' => 'context',
|
124
|
+
'.csv' => 'csv',
|
125
|
+
'.ctx' => 'context',
|
126
|
+
'.db' => 'docbook',
|
127
|
+
'.dj' => 'djot',
|
128
|
+
'.docx' => 'docx',
|
129
|
+
'.dokuwiki' => 'dokuwiki',
|
130
|
+
'.epub' => 'epub',
|
131
|
+
'.fb2' => 'fb2',
|
132
|
+
'.htm' => 'html',
|
133
|
+
'.html' => 'html',
|
134
|
+
'.icml' => 'icml',
|
135
|
+
'.ipynb' => 'ipynb',
|
136
|
+
'.json' => 'json',
|
137
|
+
'.latex' => 'latex',
|
138
|
+
'.lhs' => 'markdown',
|
139
|
+
'.ltx' => 'latex',
|
140
|
+
'.markdown' => 'markdown',
|
141
|
+
'.markua' => 'markua',
|
142
|
+
'.md' => 'markdown',
|
143
|
+
'.mdown' => 'markdown',
|
144
|
+
'.mdwn' => 'markdown',
|
145
|
+
'.mkd' => 'markdown',
|
146
|
+
'.mkdn' => 'markdown',
|
147
|
+
'.ms' => 'ms',
|
148
|
+
'.muse' => 'muse',
|
149
|
+
'.native' => 'native',
|
150
|
+
'.odt' => 'odt',
|
151
|
+
'.opml' => 'opml',
|
152
|
+
'.org' => 'org',
|
153
|
+
'.pptx' => 'pptx',
|
154
|
+
'.ris' => 'ris',
|
155
|
+
'.roff' => 'ms',
|
156
|
+
'.rst' => 'rst',
|
157
|
+
'.rtf' => 'rtf',
|
158
|
+
'.s5' => 's5',
|
159
|
+
'.t2t' => 't2t',
|
160
|
+
'.tei' => 'tei',
|
161
|
+
'.tex' => 'latex',
|
162
|
+
'.texi' => 'texinfo',
|
163
|
+
'.texinfo' => 'texinfo',
|
164
|
+
'.text' => 'markdown',
|
165
|
+
'.textile' => 'textile',
|
166
|
+
'.tsv' => 'tsv',
|
167
|
+
'.typ' => 'typst',
|
168
|
+
'.txt' => 'markdown',
|
169
|
+
'.wiki' => 'mediawiki',
|
170
|
+
'.xhtml' => 'html',
|
171
|
+
'.1' => 'man',
|
172
|
+
'.2' => 'man',
|
173
|
+
'.3' => 'man',
|
174
|
+
'.4' => 'man',
|
175
|
+
'.5' => 'man',
|
176
|
+
'.6' => 'man',
|
177
|
+
'.7' => 'man',
|
178
|
+
'.8' => 'man',
|
179
|
+
'.9' => 'man'
|
180
|
+
}.freeze
|
115
181
|
|
116
182
|
# Configuration models a pandocomatic configuration.
|
117
183
|
class Configuration
|
@@ -142,7 +208,7 @@ module Pandocomatic
|
|
142
208
|
@output = if output?
|
143
209
|
options[:output]
|
144
210
|
elsif to_stdout? options
|
145
|
-
Tempfile.new(@input.base)
|
211
|
+
Tempfile.new(@input.base) unless @input.nil?
|
146
212
|
elsif @input.is_a? Input
|
147
213
|
@input.base
|
148
214
|
end
|
@@ -238,18 +304,11 @@ module Pandocomatic
|
|
238
304
|
@options[:verbose_given] and @options[:verbose]
|
239
305
|
end
|
240
306
|
|
241
|
-
# Is the debug CLI option given?
|
242
|
-
#
|
243
|
-
# @return [Boolean]
|
244
|
-
def debug?
|
245
|
-
@options[:debug_given] and @options[:debug]
|
246
|
-
end
|
247
|
-
|
248
307
|
# Run pandocomatic in quiet mode?
|
249
308
|
#
|
250
309
|
# @return [Boolean]
|
251
310
|
def quiet?
|
252
|
-
[verbose?,
|
311
|
+
[verbose?, dry_run?].none?
|
253
312
|
end
|
254
313
|
|
255
314
|
# Is the modified only CLI option given?
|
@@ -294,6 +353,14 @@ module Pandocomatic
|
|
294
353
|
@options[:config_given]
|
295
354
|
end
|
296
355
|
|
356
|
+
# Should given feature be enabled?
|
357
|
+
#
|
358
|
+
# @param feature [Symbol] feature toggle to check
|
359
|
+
# @return [Boolean]
|
360
|
+
def feature_enabled?(feature)
|
361
|
+
@options[:enable_given] and Pandocomatic::FEATURES.include?(feature) and @options[:enable].include?(feature)
|
362
|
+
end
|
363
|
+
|
297
364
|
# Is the output CLI option given and can that output be used?
|
298
365
|
#
|
299
366
|
# @return [Boolean]
|
@@ -357,6 +424,40 @@ module Pandocomatic
|
|
357
424
|
end
|
358
425
|
end
|
359
426
|
|
427
|
+
# Get a pandoc metadata object for given source file and template.
|
428
|
+
#
|
429
|
+
# @param src [String] path to source file
|
430
|
+
# @param template_name [String] template used; optional parameter
|
431
|
+
# @return [PandocMetadata] Pandoc's metadata for given file and template.
|
432
|
+
def get_metadata(src, template_name = nil)
|
433
|
+
if extract_metadata_from? src
|
434
|
+
PandocMetadata.load_file src
|
435
|
+
else
|
436
|
+
src_format = nil
|
437
|
+
|
438
|
+
# Determine source format based on template
|
439
|
+
if template_name && @templates.key?(template_name) && @templates[template_name].pandoc?
|
440
|
+
pandoc = @templates[template_name].pandoc
|
441
|
+
src_format = pandoc['from'] if pandoc.key? 'from'
|
442
|
+
end
|
443
|
+
|
444
|
+
if src_format.nil?
|
445
|
+
# Determine source format based on extension like pandoc does.
|
446
|
+
# See https://github.com/jgm/pandoc/blob/main/src/Text/Pandoc/Format.hs
|
447
|
+
# for that mapping
|
448
|
+
src_extension = File.extname src
|
449
|
+
src_format = PANDOCS_EXTENSION_TO_FORMAT_MAPPING[src_extension]
|
450
|
+
end
|
451
|
+
|
452
|
+
if !src_format || src_format == 'markdown'
|
453
|
+
# Behave like pandoc: If no source format can be determined, assume markdown
|
454
|
+
PandocMetadata.load_file src
|
455
|
+
else
|
456
|
+
PandocMetadata.empty src_format
|
457
|
+
end
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
360
461
|
# Should the source file be converted given this Configuration?
|
361
462
|
#
|
362
463
|
# @param src [String] True if this source file matches the 'glob'
|
@@ -577,6 +678,8 @@ module Pandocomatic
|
|
577
678
|
case setting
|
578
679
|
when 'skip'
|
579
680
|
@settings['skip'] = @settings['skip'].concat(value).uniq
|
681
|
+
when 'extract-metadata-from'
|
682
|
+
@settings['extract-metadata-from'] = @settings['extract-metadata-from'].concat(value).uniq
|
580
683
|
when 'data-dir'
|
581
684
|
next # skip data-dir setting; is set once in initialization
|
582
685
|
else
|
@@ -761,6 +864,15 @@ module Pandocomatic
|
|
761
864
|
path
|
762
865
|
end
|
763
866
|
end
|
867
|
+
|
868
|
+
# Should we try to extract pandoc YAML metadata from source file?
|
869
|
+
def extract_metadata_from?(src)
|
870
|
+
if @settings.key? 'extract-metadata-from'
|
871
|
+
@settings['extract-metadata-from'].any? { |glob| File.fnmatch glob, File.basename(src) }
|
872
|
+
else
|
873
|
+
false
|
874
|
+
end
|
875
|
+
end
|
764
876
|
end
|
765
|
-
# rubocop:enable Metrics
|
766
877
|
end
|
878
|
+
# rubocop:enable Metrics
|
@@ -41,7 +41,7 @@ module Pandocomatic
|
|
41
41
|
# @param data [Object = nil] extra information attached to this
|
42
42
|
# PandocomaticError, if any; optional
|
43
43
|
def initialize(type = :unknown, error = nil, data = nil)
|
44
|
-
super
|
44
|
+
super(type.to_s.gsub('_', ' ').capitalize)
|
45
45
|
@type = type
|
46
46
|
@error = error
|
47
47
|
@data = data
|
data/lib/pandocomatic/input.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright 2019 Huub de Beer <Huub@heerdebeer.org>
|
4
|
+
# Copyright 2019—2024 Huub de Beer <Huub@heerdebeer.org>
|
5
5
|
#
|
6
6
|
# This file is part of pandocomatic.
|
7
7
|
#
|
@@ -19,8 +19,6 @@
|
|
19
19
|
# with pandocomatic. If not, see <http://www.gnu.org/licenses/>.
|
20
20
|
#++
|
21
21
|
module Pandocomatic
|
22
|
-
require_relative 'configuration'
|
23
|
-
|
24
22
|
# Generic class to handle input files and directories in a general manner.
|
25
23
|
class Input
|
26
24
|
attr_reader :errors
|