pandocomatic 0.2.4.2 → 0.2.5.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|