pandocomatic 0.2.4.2 → 0.2.5.0.alpha
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 +34 -23
- data/lib/pandocomatic/command/command.rb +7 -12
- data/lib/pandocomatic/command/convert_dir_command.rb +1 -1
- data/lib/pandocomatic/configuration.rb +234 -17
- data/lib/pandocomatic/error/cli_error.rb +2 -1
- data/lib/pandocomatic/input.rb +69 -0
- data/lib/pandocomatic/multiple_files_input.rb +82 -0
- data/lib/pandocomatic/pandoc_metadata.rb +13 -2
- data/lib/pandocomatic/pandocomatic.rb +15 -104
- data/lib/pandocomatic/printer/finish_printer.rb +9 -2
- data/lib/pandocomatic/printer/summary_printer.rb +5 -5
- data/lib/pandocomatic/printer/views/cli_error.txt +5 -0
- data/lib/pandocomatic/printer/views/help.txt +11 -4
- data/lib/pandocomatic/printer/views/version.txt +2 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e0830abb917ca87c8d072ee5a4f88fee1f2f2d8da6359f14e74f9160614b23f9
|
4
|
+
data.tar.gz: 68f2dbf9325b3ccaeeeae4c2c99b3de4486ff00a2e6c1951a6b14f3f4260232a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8c034acc735d84f56c95765a070a129bb522bfe2b6536d407dc067c86f954fad64c7679cb561551689f837d1c54186a9e6c69e7f9fa192eaf548dc948395a0b
|
7
|
+
data.tar.gz: a625b92f99fdccfc5786cb8e2e234b572f4157f4efc894bdc6ed2be39eaad54cb4d33895014e410abfc37e3e983fa9bb6b9de805fa693fa5e1bab54a1f0cebf0
|
data/lib/pandocomatic/cli.rb
CHANGED
@@ -20,9 +20,11 @@ module Pandocomatic
|
|
20
20
|
require 'optimist'
|
21
21
|
|
22
22
|
require_relative './error/cli_error.rb'
|
23
|
+
require_relative './configuration.rb'
|
24
|
+
|
23
25
|
|
24
26
|
##
|
25
|
-
# Command line options parser for pandocomatic using
|
27
|
+
# Command line options parser for pandocomatic using optimist.
|
26
28
|
#
|
27
29
|
class CLI
|
28
30
|
|
@@ -32,15 +34,13 @@ module Pandocomatic
|
|
32
34
|
#
|
33
35
|
# @param args [String, Array] A command line invocation string or a list of strings like ARGV
|
34
36
|
#
|
35
|
-
# @return [
|
36
|
-
# the
|
37
|
-
#
|
37
|
+
# @return [Configuration] The configuration for running pandocomatic given
|
38
|
+
# the command-line options.
|
38
39
|
def self.parse(args)
|
39
40
|
args = args.split if args.is_a? String
|
40
41
|
|
41
42
|
begin
|
42
|
-
|
43
|
-
options
|
43
|
+
parse_options args || Configuration.new({:help => true, :help_given => true})
|
44
44
|
rescue Optimist::CommandlineError => e
|
45
45
|
raise CLIError.new(:problematic_invocation, e, args)
|
46
46
|
end
|
@@ -49,6 +49,8 @@ module Pandocomatic
|
|
49
49
|
private
|
50
50
|
|
51
51
|
# Parse pandocomatic's global options.
|
52
|
+
#
|
53
|
+
# @return [Configuration]
|
52
54
|
def self.parse_options(args)
|
53
55
|
parser = Optimist::Parser.new do
|
54
56
|
# General options
|
@@ -63,7 +65,7 @@ module Pandocomatic
|
|
63
65
|
|
64
66
|
# What to convert and where to put it
|
65
67
|
opt :output, 'Output', :short => '-o', :type => String
|
66
|
-
opt :input, 'Input', :short => '-i', :type => String
|
68
|
+
opt :input, 'Input', :short => '-i', :type => String, :multi => true
|
67
69
|
|
68
70
|
# Version and help
|
69
71
|
opt :show_version, 'Version', :short => '-v', :long => 'version'
|
@@ -79,29 +81,38 @@ module Pandocomatic
|
|
79
81
|
|
80
82
|
options = use_custom_version options
|
81
83
|
options = use_custom_help options
|
82
|
-
|
84
|
+
|
83
85
|
if options_need_to_be_validated? options
|
84
|
-
# if no input option is specified,
|
86
|
+
# if no input option is specified, all items following the last option
|
87
|
+
# are treated as input files.
|
85
88
|
if not options[:input_given]
|
86
|
-
options[:input] = args
|
89
|
+
options[:input] = args
|
87
90
|
options[:input_given] = true
|
91
|
+
elsif not args.empty?
|
92
|
+
raise CLIError.new(:no_mixed_inputs)
|
88
93
|
end
|
89
94
|
|
90
|
-
# There should be no other options left.
|
91
|
-
raise CLIError.new(:too_many_options, nil, args) if not args.empty?
|
92
|
-
|
93
95
|
# There should be an input specified
|
94
96
|
raise CLIError.new(:no_input_given) if options[:input].nil? or options[:input].empty?
|
95
97
|
|
96
|
-
#
|
97
|
-
|
98
|
-
|
99
|
-
|
98
|
+
# Support multiple input files for conversion
|
99
|
+
multiple_inputs = 1 < options[:input].size
|
100
|
+
|
101
|
+
# The input files or directories should exist
|
102
|
+
input = options[:input].map do |input_file|
|
103
|
+
raise CLIError.new(:input_does_not_exist, nil, input_file) unless File.exist? input_file
|
104
|
+
raise CLIError.new(:input_is_not_readable, nil, input_file) unless File.readable? input_file
|
105
|
+
|
106
|
+
# If there are multiple input files, these files cannot be directories
|
107
|
+
raise CLIError.new(:multiple_input_files_only, nil, input_file) if multiple_inputs and File.directory? input_file
|
108
|
+
|
109
|
+
File.absolute_path input_file
|
110
|
+
end
|
100
111
|
|
101
112
|
if options[:output_given]
|
102
113
|
output = File.absolute_path options[:output]
|
103
114
|
# Input and output should be both files or directories
|
104
|
-
match_file_types input, output
|
115
|
+
match_file_types input.first, output
|
105
116
|
|
106
117
|
# The output, if it already exist, should be writable
|
107
118
|
raise CLIError.new(:output_is_not_writable, nil, output) unless not File.exist? output or File.writable? output
|
@@ -109,7 +120,7 @@ module Pandocomatic
|
|
109
120
|
# If the input is a directory, an output directory should be
|
110
121
|
# specified as well. If the input is a file, the output could be
|
111
122
|
# specified in the input file, or STDOUT could be used.
|
112
|
-
raise CLIError.new(:no_output_given) if File.directory? input
|
123
|
+
raise CLIError.new(:no_output_given) if not multiple_inputs and File.directory? input.first
|
113
124
|
end
|
114
125
|
|
115
126
|
# Data dir, if specified, should be an existing and readable directory
|
@@ -130,9 +141,9 @@ module Pandocomatic
|
|
130
141
|
raise CLIError.new(:config_file_is_not_a_file, nil, config) unless File.file? config
|
131
142
|
end
|
132
143
|
|
133
|
-
end
|
134
|
-
|
135
|
-
options
|
144
|
+
end
|
145
|
+
|
146
|
+
Configuration.new options, input
|
136
147
|
end
|
137
148
|
|
138
149
|
def self.options_need_to_be_validated? options
|
@@ -140,7 +151,7 @@ module Pandocomatic
|
|
140
151
|
end
|
141
152
|
|
142
153
|
#--
|
143
|
-
#Optimist has special behavior for the version and help options. To
|
154
|
+
# Optimist has special behavior for the version and help options. To
|
144
155
|
# overcome, "show_version" and "show_help" options are introduced. When
|
145
156
|
# set, these are put in the options as "version" and "help"
|
146
157
|
# respectively.
|
@@ -50,18 +50,13 @@ module Pandocomatic
|
|
50
50
|
|
51
51
|
# Reset all Commands
|
52
52
|
#
|
53
|
-
# @param
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
@@src_root = src_root
|
61
|
-
@@dry_run = dry_run
|
62
|
-
@@quiet = quiet
|
63
|
-
@@debug = debug
|
64
|
-
@@modified_only = modified_only
|
53
|
+
# @param configuration [Configuration] the configuration used to convert
|
54
|
+
def self.reset(configuration)
|
55
|
+
@@src_root = configuration.src_root
|
56
|
+
@@dry_run = configuration.dry_run?
|
57
|
+
@@quiet = configuration.quiet?
|
58
|
+
@@debug = configuration.debug?
|
59
|
+
@@modified_only = configuration.modified_only?
|
65
60
|
@@total = 0
|
66
61
|
end
|
67
62
|
|
@@ -142,7 +142,7 @@ module Pandocomatic
|
|
142
142
|
# If the source directory contains a configuration file, use it to
|
143
143
|
# reconfigure the converter. Otherwise, use the current configuration
|
144
144
|
def reconfigure(current_config, src_dir)
|
145
|
-
config_file = File.join src_dir,
|
145
|
+
config_file = File.join src_dir, Configuration::CONFIG_FILE
|
146
146
|
if File.exist? config_file then
|
147
147
|
config = current_config.reconfigure config_file
|
148
148
|
else
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright 2014
|
2
|
+
# Copyright 2014—2019 Huub de Beer <Huub@heerdebeer.org>
|
3
3
|
#
|
4
4
|
# This file is part of pandocomatic.
|
5
5
|
#
|
@@ -20,6 +20,11 @@ module Pandocomatic
|
|
20
20
|
|
21
21
|
require 'yaml'
|
22
22
|
require 'paru/pandoc'
|
23
|
+
|
24
|
+
require_relative './error/configuration_error.rb'
|
25
|
+
require_relative './command/command.rb'
|
26
|
+
require_relative './input.rb'
|
27
|
+
require_relative './multiple_files_input.rb'
|
23
28
|
|
24
29
|
# The default configuration for pandocomatic is read from
|
25
30
|
# default_configuration.yaml.
|
@@ -56,12 +61,38 @@ module Pandocomatic
|
|
56
61
|
# A Configuration object models a pandocomatic configuration.
|
57
62
|
class Configuration
|
58
63
|
|
59
|
-
#
|
60
|
-
|
61
|
-
def initialize options, data_dir, configuration_file
|
62
|
-
@data_dir = data_dir
|
64
|
+
# Pandocomatic's default configuration file
|
65
|
+
CONFIG_FILE = 'pandocomatic.yaml'
|
63
66
|
|
64
|
-
|
67
|
+
# Create a new Configuration instance based on the command-line options
|
68
|
+
def initialize options, input
|
69
|
+
@options = options
|
70
|
+
@data_dir = determine_data_dir options
|
71
|
+
config_file = determine_config_file(options, @data_dir)
|
72
|
+
|
73
|
+
load config_file unless config_file.nil? or config_file.empty?
|
74
|
+
|
75
|
+
@input = if input.nil? or input.empty? then
|
76
|
+
nil
|
77
|
+
elsif 1 < input.size then
|
78
|
+
MultipleFilesInput.new(input)
|
79
|
+
else
|
80
|
+
Input.new(input)
|
81
|
+
end
|
82
|
+
|
83
|
+
@output = if output? then
|
84
|
+
options[:output]
|
85
|
+
elsif @input.is_a? Input then
|
86
|
+
@input.base
|
87
|
+
else
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
|
91
|
+
# Extend the command classes by setting the source tree root
|
92
|
+
# directory, and the options quiet and dry-run, which are used when
|
93
|
+
# executing a command: if dry-run the command is not actually
|
94
|
+
# executed and if quiet the command is not printed to STDOUT
|
95
|
+
Command.reset(self)
|
65
96
|
end
|
66
97
|
|
67
98
|
# Read a configuration file and create a pandocomatic configuration object
|
@@ -149,6 +180,116 @@ module Pandocomatic
|
|
149
180
|
marshal_dump
|
150
181
|
end
|
151
182
|
|
183
|
+
# Is the dry run CLI option given?
|
184
|
+
#
|
185
|
+
# @return [Boolean]
|
186
|
+
def dry_run?()
|
187
|
+
@options[:dry_run_given] and @options[:dry_run]
|
188
|
+
end
|
189
|
+
|
190
|
+
# Is the quiet CLI option given?
|
191
|
+
#
|
192
|
+
# @return [Boolean]
|
193
|
+
def quiet?()
|
194
|
+
@options[:quiet_given] and @options[:quiet]
|
195
|
+
end
|
196
|
+
|
197
|
+
# Is the debug CLI option given?
|
198
|
+
#
|
199
|
+
# @return [Boolean]
|
200
|
+
def debug?()
|
201
|
+
@options[:debug_given] and @options[:debug]
|
202
|
+
end
|
203
|
+
|
204
|
+
# Is the modified only CLI option given?
|
205
|
+
#
|
206
|
+
# @return [Boolean]
|
207
|
+
def modified_only?()
|
208
|
+
@options[:modified_only_given] and @options[:modified_only]
|
209
|
+
end
|
210
|
+
|
211
|
+
# Is the version CLI option given?
|
212
|
+
#
|
213
|
+
# @return [Boolean]
|
214
|
+
def show_version?()
|
215
|
+
@options[:version_given]
|
216
|
+
end
|
217
|
+
|
218
|
+
# Is the help CLI option given?
|
219
|
+
#
|
220
|
+
# @return [Boolean]
|
221
|
+
def show_help?()
|
222
|
+
@options[:help_given]
|
223
|
+
end
|
224
|
+
|
225
|
+
# Is the data dir CLI option given?
|
226
|
+
#
|
227
|
+
# @return [Boolean]
|
228
|
+
def data_dir?()
|
229
|
+
@options[:data_dir_given]
|
230
|
+
end
|
231
|
+
|
232
|
+
# Is the config CLI option given?
|
233
|
+
#
|
234
|
+
# @return [Boolean]
|
235
|
+
def config?()
|
236
|
+
@options[:config_given]
|
237
|
+
end
|
238
|
+
|
239
|
+
# Is the output CLI option given and can that output be used?
|
240
|
+
#
|
241
|
+
# @return [Boolean]
|
242
|
+
def output?()
|
243
|
+
@options[:output_given] and @options[:output]
|
244
|
+
end
|
245
|
+
|
246
|
+
# Get the output file name
|
247
|
+
#
|
248
|
+
# @return [String]
|
249
|
+
def output()
|
250
|
+
@output
|
251
|
+
end
|
252
|
+
|
253
|
+
# Get the source root directory
|
254
|
+
#
|
255
|
+
# @return [String]
|
256
|
+
def src_root()
|
257
|
+
if @input.nil? then nil else @input.absolute_path end
|
258
|
+
end
|
259
|
+
|
260
|
+
# Have input CLI options be given?
|
261
|
+
def input?()
|
262
|
+
@options[:input_given]
|
263
|
+
end
|
264
|
+
|
265
|
+
# Get the input file name
|
266
|
+
#
|
267
|
+
# @return [String]
|
268
|
+
def input()
|
269
|
+
if @input.nil? then
|
270
|
+
nil
|
271
|
+
else
|
272
|
+
@input.name
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
# Is this Configuration for converting directories?
|
277
|
+
#
|
278
|
+
# @return [Boolean]
|
279
|
+
def directory?()
|
280
|
+
not @input.nil? and @input.directory?
|
281
|
+
end
|
282
|
+
|
283
|
+
# Clean up this configuration. This will remove temporary files
|
284
|
+
# created for the conversion process guided by this Configuration.
|
285
|
+
def clean_up!()
|
286
|
+
# If a temporary file has been created while concatenating
|
287
|
+
# multiple input files, ensure it is removed.
|
288
|
+
if @input.is_a? MultipleFilesInput then
|
289
|
+
@input.destroy!
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
152
293
|
# Should the source file be skipped given this Configuration?
|
153
294
|
#
|
154
295
|
# @param src [String] path to a source file
|
@@ -245,13 +386,22 @@ module Pandocomatic
|
|
245
386
|
end
|
246
387
|
end
|
247
388
|
|
248
|
-
|
249
|
-
|
250
|
-
|
389
|
+
destination = nil
|
390
|
+
rename_script = nil
|
391
|
+
|
392
|
+
# Output option in pandoc property has precedence
|
393
|
+
if metadata.has_pandocomatic?
|
394
|
+
pandocomatic = metadata.pandocomatic
|
395
|
+
if pandocomatic.has_key? "pandoc"
|
396
|
+
pandoc = pandocomatic["pandoc"]
|
397
|
+
destination = determine_output_in_pandoc.call pandoc
|
398
|
+
rename_script = pandoc["rename"]
|
399
|
+
end
|
400
|
+
end
|
251
401
|
|
252
402
|
# Output option in template's pandoc property is next
|
253
403
|
if destination.nil? and not template_name.nil? and not template_name.empty? then
|
254
|
-
if @templates[template_name].has_key? "pandoc"
|
404
|
+
if @templates[template_name].has_key? "pandoc"
|
255
405
|
pandoc = @templates[template_name]["pandoc"]
|
256
406
|
destination = determine_output_in_pandoc.call pandoc
|
257
407
|
rename_script ||= pandoc["rename"]
|
@@ -295,14 +445,21 @@ module Pandocomatic
|
|
295
445
|
end
|
296
446
|
|
297
447
|
if template_name.nil? or template_name.empty? then
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
448
|
+
if metadata.has_pandocomatic?
|
449
|
+
pandocomatic = metadata.pandocomatic
|
450
|
+
if pandocomatic.has_key? "pandoc"
|
451
|
+
pandoc = pandocomatic["pandoc"]
|
452
|
+
|
453
|
+
ext = use_extension.call pandoc
|
454
|
+
if not ext.nil?
|
455
|
+
extension = ext
|
456
|
+
elsif pandoc.has_key? "to"
|
457
|
+
extension = strip_extensions.call(pandoc["to"])
|
458
|
+
end
|
459
|
+
end
|
460
|
+
end
|
304
461
|
else
|
305
|
-
if @templates[template_name].has_key? "pandoc"
|
462
|
+
if @templates[template_name].has_key? "pandoc"
|
306
463
|
pandoc = @templates[template_name]["pandoc"]
|
307
464
|
ext = use_extension.call pandoc
|
308
465
|
|
@@ -669,5 +826,65 @@ module Pandocomatic
|
|
669
826
|
path.start_with? "/"
|
670
827
|
end
|
671
828
|
end
|
829
|
+
|
830
|
+
def determine_config_file(options, data_dir = Dir.pwd)
|
831
|
+
config_file = ''
|
832
|
+
|
833
|
+
if options[:config_given]
|
834
|
+
config_file = options[:config]
|
835
|
+
elsif Dir.entries(data_dir).include? CONFIG_FILE
|
836
|
+
config_file = File.join(data_dir, CONFIG_FILE)
|
837
|
+
elsif Dir.entries(Dir.pwd()).include? CONFIG_FILE
|
838
|
+
config_file = File.join(Dir.pwd(), CONFIG_FILE)
|
839
|
+
else
|
840
|
+
# Fall back to default configuration file distributed with
|
841
|
+
# pandocomatic
|
842
|
+
config_file = File.join(__dir__, 'default_configuration.yaml')
|
843
|
+
end
|
844
|
+
|
845
|
+
path = File.absolute_path config_file
|
846
|
+
|
847
|
+
raise ConfigurationError.new(:config_file_does_not_exist, nil, path) unless File.exist? path
|
848
|
+
raise ConfigurationError.new(:config_file_is_not_a_file, nil, path) unless File.file? path
|
849
|
+
raise ConfigurationError.new(:config_file_is_not_readable, nil, path) unless File.readable? path
|
850
|
+
|
851
|
+
path
|
852
|
+
end
|
853
|
+
|
854
|
+
def determine_data_dir(options)
|
855
|
+
data_dir = ''
|
856
|
+
|
857
|
+
if options[:data_dir_given]
|
858
|
+
data_dir = options[:data_dir]
|
859
|
+
else
|
860
|
+
# No data-dir option given: try to find the default one from pandoc
|
861
|
+
begin
|
862
|
+
data_dir = Paru::Pandoc.info()[:data_dir]
|
863
|
+
|
864
|
+
# If pandoc's data dir does not exist, however, fall back
|
865
|
+
# to the current directory
|
866
|
+
unless File.exist? File.absolute_path(data_dir)
|
867
|
+
data_dir = Dir.pwd
|
868
|
+
end
|
869
|
+
rescue Paru::Error => e
|
870
|
+
# If pandoc cannot be run, continuing probably does not work out
|
871
|
+
# anyway, so raise pandoc error
|
872
|
+
raise PandocError.new(:error_running_pandoc, e, data_dir)
|
873
|
+
rescue StandardError => e
|
874
|
+
# Ignore error and use the current working directory as default working directory
|
875
|
+
data_dir = Dir.pwd
|
876
|
+
end
|
877
|
+
end
|
878
|
+
|
879
|
+
# check if data directory does exist and is readable
|
880
|
+
path = File.absolute_path data_dir
|
881
|
+
|
882
|
+
raise ConfigurationError.new(:data_dir_does_not_exist, nil, path) unless File.exist? path
|
883
|
+
raise ConfigurationError.new(:data_dir_is_not_a_directory, nil, path) unless File.directory? path
|
884
|
+
raise ConfigurationError.new(:data_dir_is_not_readable, nil, path) unless File.readable? path
|
885
|
+
|
886
|
+
path
|
887
|
+
end
|
888
|
+
|
672
889
|
end
|
673
890
|
end
|
@@ -30,6 +30,8 @@ module Pandocomatic
|
|
30
30
|
# :no_input_given,
|
31
31
|
# :input_does_not_exist,
|
32
32
|
# :input_is_not_readable,
|
33
|
+
# :multiple_input_files_only,
|
34
|
+
# :no_mixed_inputs
|
33
35
|
|
34
36
|
# :no_output_given,
|
35
37
|
# :output_is_not_a_directory,
|
@@ -37,7 +39,6 @@ module Pandocomatic
|
|
37
39
|
# :output_it_not_writable,
|
38
40
|
|
39
41
|
# :unknown_option,
|
40
|
-
# :too_many_options,
|
41
42
|
# :problematic_invocation,
|
42
43
|
|
43
44
|
# :data_dir_does_not_exist,
|
@@ -0,0 +1,69 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2019 Huub de Beer <Huub@heerdebeer.org>
|
3
|
+
#
|
4
|
+
# This file is part of pandocomatic.
|
5
|
+
#
|
6
|
+
# Pandocomatic is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by the
|
8
|
+
# Free Software Foundation, either version 3 of the License, or (at your
|
9
|
+
# option) any later version.
|
10
|
+
#
|
11
|
+
# Pandocomatic is distributed in the hope that it will be useful, but
|
12
|
+
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
13
|
+
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
14
|
+
# for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License along
|
17
|
+
# with pandocomatic. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#++
|
19
|
+
module Pandocomatic
|
20
|
+
|
21
|
+
require_relative './configuration.rb'
|
22
|
+
|
23
|
+
# Generic class to handle input files and directories in a general manner.
|
24
|
+
class Input
|
25
|
+
|
26
|
+
# Create a new Input
|
27
|
+
#
|
28
|
+
# @param input [String[]] a list of input files
|
29
|
+
def initialize(input)
|
30
|
+
@input_files = input
|
31
|
+
end
|
32
|
+
|
33
|
+
# The absolute path to this Input
|
34
|
+
#
|
35
|
+
# @return String
|
36
|
+
def absolute_path()
|
37
|
+
File.absolute_path @input_files.first
|
38
|
+
end
|
39
|
+
|
40
|
+
# The base name of this Input
|
41
|
+
#
|
42
|
+
# @return String
|
43
|
+
def base()
|
44
|
+
File.basename @input_files.first
|
45
|
+
end
|
46
|
+
|
47
|
+
# The name of this input
|
48
|
+
#
|
49
|
+
# @return String
|
50
|
+
def name()
|
51
|
+
@input_files.first
|
52
|
+
end
|
53
|
+
|
54
|
+
# Is this input a directory?
|
55
|
+
#
|
56
|
+
# @return Boolean
|
57
|
+
def directory?()
|
58
|
+
File.directory? @input_files.first
|
59
|
+
end
|
60
|
+
|
61
|
+
# A string representation of this Input
|
62
|
+
#
|
63
|
+
# @return String
|
64
|
+
def to_s()
|
65
|
+
self.name
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2019 Huub de Beer <Huub@heerdebeer.org>
|
3
|
+
#
|
4
|
+
# This file is part of pandocomatic.
|
5
|
+
#
|
6
|
+
# Pandocomatic is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by the
|
8
|
+
# Free Software Foundation, either version 3 of the License, or (at your
|
9
|
+
# option) any later version.
|
10
|
+
#
|
11
|
+
# Pandocomatic is distributed in the hope that it will be useful, but
|
12
|
+
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
13
|
+
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
14
|
+
# for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License along
|
17
|
+
# with pandocomatic. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#++
|
19
|
+
module Pandocomatic
|
20
|
+
|
21
|
+
require 'tempfile'
|
22
|
+
require_relative './input.rb'
|
23
|
+
|
24
|
+
# A specific Input class to handle multiple input files
|
25
|
+
class MultipleFilesInput < Input
|
26
|
+
|
27
|
+
# Create a new MultipleFilesInput. As a side-effect a temporary file
|
28
|
+
# is created as well containing the content of all the files in input.
|
29
|
+
#
|
30
|
+
# @param input [String[]] a list with input files
|
31
|
+
def initialize(input)
|
32
|
+
super(input)
|
33
|
+
create_temp_file
|
34
|
+
end
|
35
|
+
|
36
|
+
# The name of this input
|
37
|
+
#
|
38
|
+
# @return String
|
39
|
+
def name()
|
40
|
+
@tmp_file
|
41
|
+
end
|
42
|
+
|
43
|
+
# Is this input a directory? A MultipleFilesInput cannot be a
|
44
|
+
# directory
|
45
|
+
#
|
46
|
+
# @return Boolean
|
47
|
+
def directory?()
|
48
|
+
false
|
49
|
+
end
|
50
|
+
|
51
|
+
# Destroy the temporary file created for this MultipleFilesInput
|
52
|
+
def destroy!()
|
53
|
+
if not @tmp_file.nil?
|
54
|
+
@tmp_file.close
|
55
|
+
@tmp_file.unlink
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# A string representation of this Input
|
60
|
+
#
|
61
|
+
# @return String
|
62
|
+
def to_s()
|
63
|
+
@input_files.join(" + ")
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def create_temp_file()
|
69
|
+
# Concatenate all input files into one (temporary) input file
|
70
|
+
# created in the same directory as the first input file
|
71
|
+
@tmp_file = Tempfile.new(@input_files.first, File.dirname(self.absolute_path))
|
72
|
+
|
73
|
+
@input_files.each_with_index do |filename, index|
|
74
|
+
input = File.read File.absolute_path(filename)
|
75
|
+
input = if 0 === index then input else PandocMetadata.remove_metadata(input) end
|
76
|
+
@tmp_file.write input
|
77
|
+
end
|
78
|
+
|
79
|
+
@tmp_file.rewind
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -24,6 +24,9 @@ module Pandocomatic
|
|
24
24
|
|
25
25
|
require_relative './error/pandoc_error.rb'
|
26
26
|
require_relative './error/io_error.rb'
|
27
|
+
|
28
|
+
# Regular expression to find metadata blocks in a string.
|
29
|
+
METADATA_BLOCK = /^---[ \t]*(\r\n|\r|\n)(.+?)^(?:---|\.\.\.)[ \t]*(\r\n|\r|\n)/m
|
27
30
|
|
28
31
|
# PandocMetadata represents the metadata with pandoc options set in
|
29
32
|
# templates and input files.
|
@@ -41,12 +44,20 @@ module Pandocomatic
|
|
41
44
|
end
|
42
45
|
end
|
43
46
|
|
47
|
+
# Remove all metadata from an input string
|
48
|
+
#
|
49
|
+
# @param input [String] the input to remove all metadata from
|
50
|
+
# @return [String] the input with all metadata blocks removed
|
51
|
+
def self.remove_metadata(input)
|
52
|
+
input.gsub(METADATA_BLOCK, "\n");
|
53
|
+
end
|
54
|
+
|
44
55
|
# Extract the YAML metadata from an input string
|
45
56
|
#
|
46
57
|
# @param input [String] the input string
|
47
58
|
# @return [String] the YAML data embedded in the input string
|
48
59
|
def self.pandoc2yaml(input)
|
49
|
-
mined_metadata = input.scan(
|
60
|
+
mined_metadata = input.scan(METADATA_BLOCK)
|
50
61
|
|
51
62
|
mined_metadata
|
52
63
|
.flatten
|
@@ -159,7 +170,7 @@ module Pandocomatic
|
|
159
170
|
# @return [Boolean] True if there is a pandoc options property in this
|
160
171
|
# PandocMetadata object. False otherwise.
|
161
172
|
def has_pandoc_options?()
|
162
|
-
has_pandocomatic? and pandocomatic.has_key? 'pandoc'
|
173
|
+
has_pandocomatic? and pandocomatic.has_key? 'pandoc'
|
163
174
|
end
|
164
175
|
|
165
176
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright 2014,
|
2
|
+
# Copyright 2014—2019, Huub de Beer <Huub@heerdebeer.org>
|
3
3
|
#
|
4
4
|
# This file is part of pandocomatic.
|
5
5
|
#
|
@@ -21,15 +21,13 @@ module Pandocomatic
|
|
21
21
|
Encoding.default_internal = Encoding::UTF_8
|
22
22
|
|
23
23
|
require 'paru'
|
24
|
+
require 'tempfile'
|
24
25
|
|
25
26
|
require_relative './error/pandocomatic_error.rb'
|
26
27
|
require_relative './error/pandoc_error.rb'
|
27
|
-
require_relative './error/configuration_error.rb'
|
28
28
|
|
29
29
|
require_relative './cli.rb'
|
30
30
|
|
31
|
-
require_relative './configuration.rb'
|
32
|
-
|
33
31
|
require_relative './printer/help_printer.rb'
|
34
32
|
require_relative './printer/version_printer.rb'
|
35
33
|
require_relative './printer/error_printer.rb'
|
@@ -37,7 +35,6 @@ module Pandocomatic
|
|
37
35
|
require_relative './printer/finish_printer.rb'
|
38
36
|
require_relative './printer/summary_printer.rb'
|
39
37
|
|
40
|
-
require_relative './command/command.rb'
|
41
38
|
require_relative './command/convert_dir_command.rb'
|
42
39
|
require_relative './command/convert_list_command.rb'
|
43
40
|
require_relative './command/convert_file_command.rb'
|
@@ -50,54 +47,34 @@ module Pandocomatic
|
|
50
47
|
ERROR_STATUS = 1266 # This is the sum of the ascii values of the characters in 'pandocomatic'
|
51
48
|
|
52
49
|
# Pandocomatic's current version
|
53
|
-
VERSION = [0, 2,
|
54
|
-
|
55
|
-
# Pandocomatic's default configuration file
|
56
|
-
CONFIG_FILE = 'pandocomatic.yaml'
|
57
|
-
|
50
|
+
VERSION = [0, 2, 5, 0, "α"]
|
51
|
+
|
58
52
|
# Run pandocomatic given options
|
59
53
|
#
|
60
54
|
# @param args [String[]] list of options to configure pandocomatic
|
61
55
|
def self.run(args)
|
62
56
|
begin
|
63
57
|
start_time = Time.now
|
64
|
-
|
58
|
+
configuration = CLI.parse args
|
65
59
|
|
66
|
-
if
|
60
|
+
if configuration.show_version?
|
67
61
|
# The version option has precedence over all other options; if
|
68
62
|
# given, the version is printed
|
69
63
|
VersionPrinter.new(VERSION).print
|
70
|
-
elsif
|
64
|
+
elsif configuration.show_help?
|
71
65
|
# The help option has precedence over all other options except the
|
72
66
|
# version option. If given, the help is printed.
|
73
67
|
HelpPrinter.new().print
|
74
68
|
else
|
75
69
|
# Run the pandocomatic converter configured according to the options
|
76
70
|
# given.
|
77
|
-
|
78
|
-
output = options[:output]
|
79
|
-
configuration = configure options
|
80
|
-
|
81
|
-
# Extend the command classes by setting the source tree root
|
82
|
-
# directory, and the options quiet and dry-run, which are used when
|
83
|
-
# executing a command: if dry-run the command is not actually
|
84
|
-
# executed and if quiet the command is not printed to STDOUT
|
85
|
-
src_root = File.absolute_path input
|
86
|
-
dry_run = if options[:dry_run_given] then options[:dry_run] else false end
|
87
|
-
quiet = if options[:quiet_given] then options[:quiet] else false end
|
88
|
-
debug = if options[:debug_given] and not quiet then options[:debug] else false end
|
89
|
-
modified_only = if options[:modified_only_given] then options[:modified_only_given] else false end
|
90
|
-
|
91
|
-
Command.reset(src_root, dry_run, quiet, debug, modified_only)
|
92
|
-
|
71
|
+
#
|
93
72
|
# Pandocomatic has two modes: converting a directory tree or
|
94
73
|
# converting a single file. The mode is selected by the input.
|
95
|
-
if
|
96
|
-
command = ConvertDirCommand.new(configuration, input, output)
|
74
|
+
if configuration.directory?
|
75
|
+
command = ConvertDirCommand.new(configuration, configuration.input, configuration.output)
|
97
76
|
else
|
98
|
-
|
99
|
-
|
100
|
-
command = ConvertFileMultipleCommand.new(configuration, input, destination)
|
77
|
+
command = ConvertFileMultipleCommand.new(configuration, configuration.input, configuration.output)
|
101
78
|
command.make_quiet unless command.subcommands.size > 1
|
102
79
|
end
|
103
80
|
|
@@ -112,14 +89,14 @@ module Pandocomatic
|
|
112
89
|
# Pandocomatic is successfully configured: running the
|
113
90
|
# actual conversion now. But first a short summary of the
|
114
91
|
# process to execute is printed.
|
115
|
-
SummaryPrinter.new(command,
|
92
|
+
SummaryPrinter.new(command, configuration).print unless configuration.quiet? or not command.directory?
|
116
93
|
|
117
94
|
# Depending on the options dry-run and quiet, the command.execute
|
118
95
|
# method will actually performing the commands (dry-run = false) and
|
119
96
|
# print the command to STDOUT (quiet = false)
|
120
97
|
command.execute()
|
121
98
|
|
122
|
-
FinishPrinter.new(command,
|
99
|
+
FinishPrinter.new(command, configuration, start_time).print unless configuration.quiet?
|
123
100
|
end
|
124
101
|
rescue PandocomaticError => e
|
125
102
|
# Report the error and break off the conversion process.
|
@@ -130,75 +107,9 @@ module Pandocomatic
|
|
130
107
|
# for now. This is likely a bug: ask the user to report it.
|
131
108
|
warn "An unexpected error has occurred. You can report this bug via https://github.com/htdebeer/pandocomatic/issues/new."
|
132
109
|
raise e
|
110
|
+
ensure
|
111
|
+
configuration.clean_up!
|
133
112
|
end
|
134
113
|
end
|
135
|
-
|
136
|
-
private
|
137
|
-
|
138
|
-
def self.determine_config_file(options, data_dir = Dir.pwd)
|
139
|
-
config_file = ''
|
140
|
-
|
141
|
-
if options[:config_given]
|
142
|
-
config_file = options[:config]
|
143
|
-
elsif Dir.entries(data_dir).include? CONFIG_FILE
|
144
|
-
config_file = File.join(data_dir, CONFIG_FILE)
|
145
|
-
elsif Dir.entries(Dir.pwd()).include? CONFIG_FILE
|
146
|
-
config_file = File.join(Dir.pwd(), CONFIG_FILE)
|
147
|
-
else
|
148
|
-
# Fall back to default configuration file distributed with
|
149
|
-
# pandocomatic
|
150
|
-
config_file = File.join(__dir__, 'default_configuration.yaml')
|
151
|
-
end
|
152
|
-
|
153
|
-
path = File.absolute_path config_file
|
154
|
-
|
155
|
-
raise ConfigurationError.new(:config_file_does_not_exist, nil, path) unless File.exist? path
|
156
|
-
raise ConfigurationError.new(:config_file_is_not_a_file, nil, path) unless File.file? path
|
157
|
-
raise ConfigurationError.new(:config_file_is_not_readable, nil, path) unless File.readable? path
|
158
|
-
|
159
|
-
path
|
160
|
-
end
|
161
|
-
|
162
|
-
def self.determine_data_dir(options)
|
163
|
-
data_dir = ''
|
164
|
-
|
165
|
-
if options[:data_dir_given]
|
166
|
-
data_dir = options[:data_dir]
|
167
|
-
else
|
168
|
-
# No data-dir option given: try to find the default one from pandoc
|
169
|
-
begin
|
170
|
-
data_dir = Paru::Pandoc.info()[:data_dir]
|
171
|
-
|
172
|
-
# If pandoc's data dir does not exist, however, fall back
|
173
|
-
# to the current directory
|
174
|
-
unless File.exist? File.absolute_path(data_dir)
|
175
|
-
data_dir = Dir.pwd
|
176
|
-
end
|
177
|
-
rescue Paru::Error => e
|
178
|
-
# If pandoc cannot be run, continuing probably does not work out
|
179
|
-
# anyway, so raise pandoc error
|
180
|
-
raise PandocError.new(:error_running_pandoc, e, data_dir)
|
181
|
-
rescue StandardError => e
|
182
|
-
# Ignore error and use the current working directory as default working directory
|
183
|
-
data_dir = Dir.pwd
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
# check if data directory does exist and is readable
|
188
|
-
path = File.absolute_path data_dir
|
189
|
-
|
190
|
-
raise ConfigurationError.new(:data_dir_does_not_exist, nil, path) unless File.exist? path
|
191
|
-
raise ConfigurationError.new(:data_dir_is_not_a_directory, nil, path) unless File.directory? path
|
192
|
-
raise ConfigurationError.new(:data_dir_is_not_readable, nil, path) unless File.readable? path
|
193
|
-
|
194
|
-
path
|
195
|
-
end
|
196
|
-
|
197
|
-
def self.configure(options)
|
198
|
-
data_dir = determine_data_dir options
|
199
|
-
config_file = determine_config_file options, data_dir
|
200
|
-
Configuration.new options, data_dir, config_file
|
201
|
-
end
|
202
|
-
|
203
114
|
end
|
204
115
|
end
|
@@ -25,8 +25,13 @@ module Pandocomatic
|
|
25
25
|
MINUTE = 60
|
26
26
|
|
27
27
|
# Create a new FinishPrinter
|
28
|
-
|
29
|
-
|
28
|
+
#
|
29
|
+
# @param command [Command] the command to finish
|
30
|
+
# @param configuration [Configuration] the configuration of the
|
31
|
+
# pandocomatic invokation
|
32
|
+
# @param start_time [Time] the time the command was started
|
33
|
+
def initialize(command, configuration, start_time)
|
34
|
+
super command, configuration
|
30
35
|
set_template 'finish.txt'
|
31
36
|
|
32
37
|
@start_time = start_time
|
@@ -34,6 +39,8 @@ module Pandocomatic
|
|
34
39
|
end
|
35
40
|
|
36
41
|
# Calculate the duration of the whole conversion process
|
42
|
+
#
|
43
|
+
# @erturn [Number]
|
37
44
|
def duration()
|
38
45
|
seconds = @end_time - @start_time
|
39
46
|
if seconds > MINUTE
|
@@ -25,13 +25,13 @@ module Pandocomatic
|
|
25
25
|
# Create a new SummaryPrinter
|
26
26
|
#
|
27
27
|
# @param command [Command] the command to summarize
|
28
|
-
# @param
|
29
|
-
#
|
30
|
-
def initialize(command,
|
28
|
+
# @param configuration [Configuration] the configuration of the
|
29
|
+
# pandocomatic invokation
|
30
|
+
def initialize(command, configuration)
|
31
31
|
super 'summary.txt'
|
32
32
|
@command = command
|
33
|
-
@input = input
|
34
|
-
@output = output
|
33
|
+
@input = configuration.input.to_s
|
34
|
+
@output = configuration.output
|
35
35
|
end
|
36
36
|
|
37
37
|
# A string representation of the commands being executed
|
@@ -1,6 +1,11 @@
|
|
1
1
|
<%=@error.message%>: <% case @error.type
|
2
2
|
when :no_input_given%>
|
3
3
|
Specify the input file or directory with the option `--input PATH`.
|
4
|
+
<% when :no_mixed_inputs%>
|
5
|
+
Using both the `--input/-i` options and extra input parameters is not allowed.
|
6
|
+
Use either only `--input/-i` options or only input parameters.
|
7
|
+
<% when :multiple_input_files_only %>
|
8
|
+
When specifying multiple inputs, only files are allowed. '<%= @error.data %>' is a directory.
|
4
9
|
<% when :unknown_option %>
|
5
10
|
See `pandocomatic --help` which options are allowed.
|
6
11
|
<% when :too_many_options %>
|
@@ -59,8 +59,15 @@ OPTIONS
|
|
59
59
|
TRUE
|
60
60
|
|
61
61
|
- templates:
|
62
|
+
- cleanup: [SCRIPTS] paths to scripts to run after a
|
63
|
+
conversion is finished, i.e. after the last
|
64
|
+
postprocessor is run.
|
62
65
|
- glob: [GLOB PATTERNS] files to convert using this
|
63
66
|
template.
|
67
|
+
- setup: [SCRIPTS] paths to scripts to run before a
|
68
|
+
conversion is started, i.e. before any preprocessor is
|
69
|
+
run.
|
70
|
+
- metadata: [YAML properties] metadata properties
|
64
71
|
- preprocessors: [SCRIPTS] paths to scripts to run before
|
65
72
|
converting with pandoc.
|
66
73
|
- postprocessors: [SCRIPTS] paths to scripts to run after
|
@@ -111,11 +118,11 @@ SEE ALSO
|
|
111
118
|
- Pandocomatic's documentation
|
112
119
|
https://heerdebeer.org/Software/markdown/pandocomatic/
|
113
120
|
|
114
|
-
- Pandoc's
|
115
|
-
|
121
|
+
- Pandoc's user guide
|
122
|
+
https://pandoc.org/MANUAL.html
|
116
123
|
|
117
124
|
- YAML website
|
118
|
-
|
125
|
+
https://yaml.org/
|
119
126
|
|
120
127
|
AUTHOR
|
121
128
|
|
@@ -123,7 +130,7 @@ AUTHOR
|
|
123
130
|
|
124
131
|
LICENSE
|
125
132
|
|
126
|
-
Copyright 2014
|
133
|
+
Copyright 2014—2019 Huub de Beer <Huub@heerdebeer.org>
|
127
134
|
|
128
135
|
Pandocomatic is free software: you can redistribute it and/or modify
|
129
136
|
it under the terms of the GNU General Public License as published by the
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pandocomatic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.5.0.alpha
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Huub de Beer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-03-
|
11
|
+
date: 2019-03-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: paru
|
@@ -105,6 +105,8 @@ files:
|
|
105
105
|
- lib/pandocomatic/error/pandoc_error.rb
|
106
106
|
- lib/pandocomatic/error/pandocomatic_error.rb
|
107
107
|
- lib/pandocomatic/error/processor_error.rb
|
108
|
+
- lib/pandocomatic/input.rb
|
109
|
+
- lib/pandocomatic/multiple_files_input.rb
|
108
110
|
- lib/pandocomatic/pandoc_metadata.rb
|
109
111
|
- lib/pandocomatic/pandocomatic.rb
|
110
112
|
- lib/pandocomatic/printer/command_printer.rb
|
@@ -148,9 +150,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
148
150
|
version: '0'
|
149
151
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
150
152
|
requirements:
|
151
|
-
- - "
|
153
|
+
- - ">"
|
152
154
|
- !ruby/object:Gem::Version
|
153
|
-
version:
|
155
|
+
version: 1.3.1
|
154
156
|
requirements:
|
155
157
|
- pandoc, a universal document converer <http://pandoc.org>
|
156
158
|
rubyforge_project:
|