epuber 0.9.4 → 0.10.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/epuber/checker/text_checker.rb +1 -2
- data/lib/epuber/checker.rb +3 -7
- data/lib/epuber/command/build.rb +43 -7
- data/lib/epuber/command/init.rb +5 -5
- data/lib/epuber/command/server.rb +1 -1
- data/lib/epuber/command.rb +24 -19
- data/lib/epuber/compiler/compilation_context.rb +8 -4
- data/lib/epuber/compiler/file_resolver.rb +1 -1
- data/lib/epuber/compiler/file_types/source_file.rb +2 -2
- data/lib/epuber/compiler/file_types/xhtml_file.rb +7 -15
- data/lib/epuber/compiler/xhtml_processor.rb +2 -2
- data/lib/epuber/compiler.rb +13 -10
- data/lib/epuber/config.rb +35 -14
- data/lib/epuber/epubcheck.rb +82 -2
- data/lib/epuber/from_file/from_file_executor.rb +9 -9
- data/lib/epuber/plugin.rb +1 -1
- data/lib/epuber/server.rb +5 -5
- data/lib/epuber/transformer/book_transformer.rb +30 -12
- data/lib/epuber/user_interface.rb +13 -218
- data/lib/epuber/utils/location.rb +14 -0
- data/lib/epuber/utils/logger/abstract_logger.rb +214 -0
- data/lib/epuber/utils/logger/console_logger.rb +122 -0
- data/lib/epuber/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6190500e356c8d6fd0d642f6e39f2f606948933bee1b17f1285add446e5bdd6d
|
4
|
+
data.tar.gz: 63719103a8cce152f0cbb63ba72ab086064e0f5cbaf03c926fad293342be1c42
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd5056baa29e1b15c5ecad2e570969a21247dec9df18d1f0e18575e4a801c0427b66b20a20a6af44a17889e5b455cc17fb55e042c203e6f154046e648630fa6b
|
7
|
+
data.tar.gz: 07a96a039ff2a06774725ca1187bc7e8c09a938513893c52b8f2d7bf6d467f7febd45529cd7beabe1ed746c7dfc4118a7936677b890681c7840edbfe4c31e8dd
|
@@ -61,8 +61,7 @@ module Epuber
|
|
61
61
|
matches = text.to_enum(:scan, regexp).map { Regexp.last_match }
|
62
62
|
matches.each do |match|
|
63
63
|
# @type match [MatchData]
|
64
|
-
UI.
|
65
|
-
Config.instance.pretty_path_from_project(file_path))
|
64
|
+
UI.warning MatchProblem.new(match, message, Config.instance.pretty_path_from_project(file_path))
|
66
65
|
end
|
67
66
|
end
|
68
67
|
|
data/lib/epuber/checker.rb
CHANGED
@@ -17,16 +17,12 @@ module Epuber
|
|
17
17
|
}.merge(super)
|
18
18
|
end
|
19
19
|
|
20
|
-
def warning(messsage, location:
|
20
|
+
def warning(messsage, location: caller_locations.first)
|
21
21
|
UI.warning(messsage, location: location)
|
22
22
|
end
|
23
23
|
|
24
|
-
def error(messsage, location:
|
25
|
-
|
26
|
-
UI.error!(messsage, location: location)
|
27
|
-
else
|
28
|
-
UI.error(messsage, location: location)
|
29
|
-
end
|
24
|
+
def error(messsage, location: caller_locations.first)
|
25
|
+
UI.error(messsage, location: location)
|
30
26
|
end
|
31
27
|
end
|
32
28
|
end
|
data/lib/epuber/command/build.rb
CHANGED
@@ -40,7 +40,7 @@ module Epuber
|
|
40
40
|
@release_version = argv.flag?('release', false)
|
41
41
|
@use_cache = argv.flag?('cache', true)
|
42
42
|
|
43
|
-
|
43
|
+
UI.logger.debug_steps_times = argv.flag?('debug-steps-times', false)
|
44
44
|
|
45
45
|
super(argv)
|
46
46
|
end
|
@@ -56,7 +56,7 @@ module Epuber
|
|
56
56
|
def run
|
57
57
|
super
|
58
58
|
|
59
|
-
UI.
|
59
|
+
UI.info "building book `#{Config.instance.pretty_path_from_project(book.file_path)}`"
|
60
60
|
|
61
61
|
if @release_version
|
62
62
|
# Remove all previous versions of compiled files
|
@@ -77,9 +77,7 @@ module Epuber
|
|
77
77
|
FileUtils.remove_file(archive_name) if ::File.exist?(archive_name)
|
78
78
|
|
79
79
|
archive_path = compiler.archive(archive_name)
|
80
|
-
|
81
|
-
Epubcheck.check(archive_path)
|
82
|
-
|
80
|
+
run_epubcheck(archive_path, build_path)
|
83
81
|
convert_epub_to_mobi(archive_path, "#{::File.basename(archive_path, '.epub')}.mobi") if target.create_mobi
|
84
82
|
|
85
83
|
Epuber::Config.instance.release_build = false
|
@@ -94,13 +92,19 @@ module Epuber
|
|
94
92
|
use_cache: @use_cache)
|
95
93
|
archive_path = compiler.archive(configuration_suffix: 'debug')
|
96
94
|
|
97
|
-
|
95
|
+
run_epubcheck(archive_path, build_path) if @should_check
|
98
96
|
|
99
97
|
convert_epub_to_mobi(archive_path, "#{::File.basename(archive_path, '.epub')}.mobi") if target.create_mobi
|
100
98
|
end
|
101
99
|
end
|
102
100
|
|
103
|
-
|
101
|
+
# Exit with error if there are any errors
|
102
|
+
if (@release_version || @should_check) && Epuber::UI.logger.error?
|
103
|
+
exit(1)
|
104
|
+
else
|
105
|
+
UI.info('🎉 Build finished successfully.'.ansi.green)
|
106
|
+
write_lockfile
|
107
|
+
end
|
104
108
|
end
|
105
109
|
|
106
110
|
private
|
@@ -131,6 +135,38 @@ module Epuber
|
|
131
135
|
path
|
132
136
|
end
|
133
137
|
|
138
|
+
def run_epubcheck(archive_path, build_dir)
|
139
|
+
UI.info("Running Epubcheck for #{archive_path}")
|
140
|
+
|
141
|
+
report = Epubcheck.check(archive_path)
|
142
|
+
report.problems.each do |problem|
|
143
|
+
relative_path = problem.location.path.sub("#{archive_path}/", '')
|
144
|
+
file_path = ::File.join(build_dir, relative_path)
|
145
|
+
|
146
|
+
nice_path = Config.instance.pretty_path_from_project(file_path)
|
147
|
+
content = ::File.read(file_path)
|
148
|
+
|
149
|
+
log_level = case problem.level
|
150
|
+
when :fatal, :error then :error
|
151
|
+
when :warning then :warning
|
152
|
+
else :info
|
153
|
+
end
|
154
|
+
message = "#{problem.level}(#{problem.code}): #{problem.message}"
|
155
|
+
|
156
|
+
p = Compiler::Problem.new(problem.level, message, content, line: problem.location.lineno,
|
157
|
+
column: problem.location.column,
|
158
|
+
length: 1,
|
159
|
+
file_path: nice_path)
|
160
|
+
UI.send(log_level, p, backtrace: nil)
|
161
|
+
end
|
162
|
+
|
163
|
+
if report.error?
|
164
|
+
UI.error('Epubcheck found some errors in epub file.')
|
165
|
+
else
|
166
|
+
UI.info('Epubcheck finished successfully.')
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
134
170
|
def find_calibre_app
|
135
171
|
locations = `mdfind "kMDItemCFBundleIdentifier == net.kovidgoyal.calibre"`.split("\n")
|
136
172
|
UI.error!("Can't find location of calibre.app to convert EPUB to MOBI.") if locations.empty?
|
data/lib/epuber/command/init.rb
CHANGED
@@ -52,7 +52,7 @@ module Epuber
|
|
52
52
|
private
|
53
53
|
|
54
54
|
def print_good_bye(book_id)
|
55
|
-
UI.
|
55
|
+
UI.info <<~TEXT.ansi.green
|
56
56
|
Project initialized, please review #{book_id}.bookspec file, remove comments and fill some attributes like book title.
|
57
57
|
TEXT
|
58
58
|
end
|
@@ -124,7 +124,7 @@ module Epuber
|
|
124
124
|
#
|
125
125
|
def write(file_path, string)
|
126
126
|
File.write(file_path, string)
|
127
|
-
UI.
|
127
|
+
UI.info " #{'create'.ansi.green} #{file_path}"
|
128
128
|
end
|
129
129
|
|
130
130
|
# @param [String] string text to file
|
@@ -148,7 +148,7 @@ module Epuber
|
|
148
148
|
existing_content << "\n"
|
149
149
|
|
150
150
|
File.write(file_path, existing_content)
|
151
|
-
UI.
|
151
|
+
UI.info " #{'update'.ansi.green} #{file_path}"
|
152
152
|
end
|
153
153
|
|
154
154
|
# @param [String] dir_path path to dir
|
@@ -157,7 +157,7 @@ module Epuber
|
|
157
157
|
#
|
158
158
|
def create_folder(dir_path)
|
159
159
|
FileUtils.mkdir_p(dir_path)
|
160
|
-
UI.
|
160
|
+
UI.info " #{'create'.ansi.green} #{dir_path}/"
|
161
161
|
end
|
162
162
|
|
163
163
|
# @param [String] text
|
@@ -169,7 +169,7 @@ module Epuber
|
|
169
169
|
result = $stdin.gets.chomp
|
170
170
|
|
171
171
|
while result.empty?
|
172
|
-
UI.
|
172
|
+
UI.info 'Value cannot be empty, please fill it!'.ansi.red
|
173
173
|
print text
|
174
174
|
result = $stdin.gets.chomp
|
175
175
|
end
|
@@ -51,7 +51,7 @@ module Epuber
|
|
51
51
|
if @open_web_browser
|
52
52
|
system "open #{uri}"
|
53
53
|
else
|
54
|
-
UI.
|
54
|
+
UI.info 'Web browser can be automatically opened by adding --open flag, see --help'
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
data/lib/epuber/command.rb
CHANGED
@@ -25,32 +25,23 @@ module Epuber
|
|
25
25
|
self.plugin_prefixes = plugin_prefixes + %w[epuber]
|
26
26
|
|
27
27
|
def self.run(argv = [])
|
28
|
-
UI.current_command = self
|
29
28
|
super
|
30
|
-
UI.current_command = nil
|
31
29
|
rescue Interrupt
|
32
30
|
UI.error('[!] Cancelled')
|
33
31
|
rescue StandardError => e
|
34
32
|
UI.error!(e)
|
35
|
-
|
36
|
-
UI.current_command = nil
|
37
33
|
end
|
38
34
|
|
39
|
-
def
|
35
|
+
def initialize(argv)
|
40
36
|
super
|
41
|
-
UI.current_command = self
|
42
|
-
end
|
43
37
|
|
44
|
-
|
45
|
-
UI.current_command = self
|
38
|
+
UI.logger.verbose = verbose?
|
46
39
|
end
|
47
40
|
|
48
|
-
|
41
|
+
def run; end
|
49
42
|
|
50
43
|
protected
|
51
44
|
|
52
|
-
attr_writer :debug_steps_times
|
53
|
-
|
54
45
|
# @return [Epuber::Book::Book]
|
55
46
|
#
|
56
47
|
def book
|
@@ -62,9 +53,16 @@ module Epuber
|
|
62
53
|
# @raise PlainInformative if no .bookspec file don't exists or there are too many
|
63
54
|
#
|
64
55
|
def verify_one_bookspec_exists!
|
65
|
-
|
66
|
-
|
67
|
-
|
56
|
+
project_path = Config.instance.project_path
|
57
|
+
bookspec_files = Config.find_bookspec_files(project_path)
|
58
|
+
|
59
|
+
if bookspec_files.empty?
|
60
|
+
raise PlainInformative, "No `.bookspec' found in the project directory (or in any parent folders)."
|
61
|
+
end
|
62
|
+
|
63
|
+
if bookspec_files.count > 1
|
64
|
+
raise PlainInformative, "Multiple `.bookspec' found in directory (directory: #{project_path})"
|
65
|
+
end
|
68
66
|
end
|
69
67
|
|
70
68
|
def write_lockfile
|
@@ -76,10 +74,17 @@ module Epuber
|
|
76
74
|
def pre_build_checks
|
77
75
|
Config.instance.warn_for_outdated_versions!
|
78
76
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
77
|
+
# remove build caches if we are using different version of Epuber or Bade
|
78
|
+
if !Config.instance.same_version_as_last_run? && File.exist?(Config.instance.working_path)
|
79
|
+
UI.warning('Using different version of Epuber or Bade, removing all build caches')
|
80
|
+
Config.instance.remove_build_caches
|
81
|
+
end
|
82
|
+
|
83
|
+
# ensure we are in the project directory
|
84
|
+
if Dir.pwd != Config.instance.project_path
|
85
|
+
UI.debug("Changing directory to project directory: #{Config.instance.project_path}")
|
86
|
+
Dir.chdir(Config.instance.project_path)
|
87
|
+
end
|
83
88
|
end
|
84
89
|
end
|
85
90
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
3
|
module Epuber
|
5
4
|
class Compiler
|
6
5
|
class CompilationContext
|
@@ -37,13 +36,14 @@ module Epuber
|
|
37
36
|
file_resolver.add_file(file)
|
38
37
|
end
|
39
38
|
plugin
|
40
|
-
rescue LoadError
|
41
|
-
UI.error "Can't find plugin at path #{path}"
|
39
|
+
rescue LoadError => e
|
40
|
+
UI.error "Can't find plugin at path #{path}, #{e}"
|
42
41
|
end.compact
|
43
42
|
end
|
44
43
|
|
45
44
|
# @param [Class] klass class of thing you want to perform (Checker or Transformer)
|
46
45
|
# @param [Symbol] source_type source type of that thing (Checker or Transformer)
|
46
|
+
# @param [String] processing_time_step_name name of step for processing time
|
47
47
|
#
|
48
48
|
# @yield
|
49
49
|
# @yieldparam [Epuber::CheckerTransformerBase] instance of checker or transformer
|
@@ -58,7 +58,11 @@ module Epuber
|
|
58
58
|
next if instance.source_type != source_type
|
59
59
|
next if instance.options.include?(:run_only_before_release) && !release_build
|
60
60
|
|
61
|
-
|
61
|
+
location = instance.block.source_location.map(&:to_s).join(':')
|
62
|
+
message = "performing #{source_type.inspect} from plugin #{location}"
|
63
|
+
UI.print_step_processing_time(message) do
|
64
|
+
yield instance
|
65
|
+
end
|
62
66
|
end
|
63
67
|
end
|
64
68
|
end
|
@@ -27,7 +27,7 @@ module Epuber
|
|
27
27
|
|
28
28
|
PATH_TYPES = [:spine, :manifest, :package, nil].freeze
|
29
29
|
|
30
|
-
# @return [String] path where should look for source files
|
30
|
+
# @return [String] path where should look for source files (relative to project root)
|
31
31
|
#
|
32
32
|
attr_reader :source_path
|
33
33
|
|
@@ -6,7 +6,7 @@ module Epuber
|
|
6
6
|
require_relative 'abstract_file'
|
7
7
|
|
8
8
|
class SourceFile < AbstractFile
|
9
|
-
# @return [String] relative source path
|
9
|
+
# @return [String] relative source path (from project root)
|
10
10
|
#
|
11
11
|
attr_reader :source_path
|
12
12
|
|
@@ -133,7 +133,7 @@ module Epuber
|
|
133
133
|
rescue XHTMLProcessor::UnparseableLinkError,
|
134
134
|
FileFinders::FileNotFoundError,
|
135
135
|
FileFinders::MultipleFilesFoundError => e
|
136
|
-
UI.
|
136
|
+
UI.error(e.to_s, location: location)
|
137
137
|
return nil
|
138
138
|
end
|
139
139
|
end
|
@@ -142,18 +142,14 @@ module Epuber
|
|
142
142
|
end
|
143
143
|
|
144
144
|
# perform transformations
|
145
|
-
|
146
|
-
|
147
|
-
xhtml_string = transformer.call(final_destination_path, xhtml_string, compilation_context)
|
148
|
-
end
|
145
|
+
compilation_context.perform_plugin_things(Transformer, :result_text_xhtml_string) do |transformer|
|
146
|
+
xhtml_string = transformer.call(final_destination_path, xhtml_string, compilation_context)
|
149
147
|
end
|
150
148
|
|
151
149
|
# perform custom validation
|
152
150
|
if compilation_context.should_check
|
153
|
-
|
154
|
-
|
155
|
-
checker.call(final_destination_path, xhtml_string, compilation_context)
|
156
|
-
end
|
151
|
+
compilation_context.perform_plugin_things(Checker, :result_text_xhtml_string) do |checker|
|
152
|
+
checker.call(final_destination_path, xhtml_string, compilation_context)
|
157
153
|
end
|
158
154
|
end
|
159
155
|
|
@@ -175,7 +171,7 @@ module Epuber
|
|
175
171
|
# @param [Compiler::CompilationContext] compilation_context
|
176
172
|
# @param [Hash<String, XHTMLFile>] global_ids
|
177
173
|
#
|
178
|
-
def process_global_ids(
|
174
|
+
def process_global_ids(_compilation_context, global_ids)
|
179
175
|
return if self.global_ids.empty? && global_links.empty?
|
180
176
|
|
181
177
|
xhtml_doc = XHTMLProcessor.xml_document_from_string(File.read(final_destination_path), final_destination_path)
|
@@ -196,12 +192,8 @@ module Epuber
|
|
196
192
|
node['href'] = "#{rel_path}##{href}"
|
197
193
|
else
|
198
194
|
message = "Can't find global id '#{href}' from link in file #{source_path}"
|
199
|
-
location =
|
200
|
-
|
201
|
-
UI.error!(message, location: location)
|
202
|
-
else
|
203
|
-
UI.warning(message, location: location)
|
204
|
-
end
|
195
|
+
location = Epuber::Location.new(path: final_destination_path, lineno: node.line)
|
196
|
+
UI.error(message, location: location)
|
205
197
|
end
|
206
198
|
end
|
207
199
|
|
@@ -25,7 +25,7 @@ module Epuber
|
|
25
25
|
|
26
26
|
if /\A[\n\r ]+(<\?xml)/ =~ text
|
27
27
|
UI.warning('XML header must be at the beginning of document',
|
28
|
-
location:
|
28
|
+
location: Epuber::Location.new(path: file_path, lineno: 1))
|
29
29
|
|
30
30
|
text = text.lstrip
|
31
31
|
end
|
@@ -198,7 +198,7 @@ module Epuber
|
|
198
198
|
# @param [Symbol | Array<Symbol>] groups groups of the searching file, could be for example :image when searching
|
199
199
|
# for file from tag <img>
|
200
200
|
# @param [String] file_path path to file from which is searching for other file
|
201
|
-
# @param [Epuber::Compiler::
|
201
|
+
# @param [Epuber::Compiler::FileFinders::Abstract] file_finder finder for searching for files
|
202
202
|
#
|
203
203
|
# @raise UnparseableLinkError, FileFinder::FileNotFoundError, FileFinder::MultipleFilesFoundError
|
204
204
|
#
|
data/lib/epuber/compiler.rb
CHANGED
@@ -71,7 +71,7 @@ module Epuber
|
|
71
71
|
|
72
72
|
FileUtils.mkdir_p(build_folder)
|
73
73
|
|
74
|
-
UI.
|
74
|
+
UI.info " #{<<~MSG}"
|
75
75
|
building target #{@target.name.inspect} (build dir: #{Config.instance.pretty_path_from_project(build_folder)})
|
76
76
|
MSG
|
77
77
|
|
@@ -89,6 +89,7 @@ module Epuber
|
|
89
89
|
process_all_target_files
|
90
90
|
generate_other_files
|
91
91
|
|
92
|
+
# run :after_all_text_files transformers
|
92
93
|
compilation_context.perform_plugin_things(Transformer, :after_all_text_files) do |transformer|
|
93
94
|
transformer.call(@book, compilation_context)
|
94
95
|
end
|
@@ -131,7 +132,7 @@ module Epuber
|
|
131
132
|
old_paths = zip_file.instance_eval { @entry_set.entries.map(&:name) }
|
132
133
|
diff = old_paths - new_paths
|
133
134
|
diff.each do |file_to_remove|
|
134
|
-
UI.
|
135
|
+
UI.debug "removing file from result EPUB: #{file_to_remove}"
|
135
136
|
zip_file.remove(file_to_remove)
|
136
137
|
end
|
137
138
|
end
|
@@ -174,7 +175,7 @@ module Epuber
|
|
174
175
|
.select { |d| File.directory?(d) }
|
175
176
|
.select { |d| (Dir.entries(d) - %w[. ..]).empty? }
|
176
177
|
.each do |d|
|
177
|
-
UI.
|
178
|
+
UI.debug "removing empty folder `#{d}`"
|
178
179
|
Dir.rmdir(d)
|
179
180
|
end
|
180
181
|
end
|
@@ -188,7 +189,7 @@ module Epuber
|
|
188
189
|
end
|
189
190
|
unnecessary_paths.each do |path|
|
190
191
|
if compilation_context.verbose?
|
191
|
-
UI.
|
192
|
+
UI.debug "removing unnecessary file: `#{Config.instance.pretty_path_from_project(path)}`"
|
192
193
|
end
|
193
194
|
|
194
195
|
File.delete(path)
|
@@ -283,11 +284,11 @@ module Epuber
|
|
283
284
|
#
|
284
285
|
def process_all_target_files
|
285
286
|
@file_resolver.manifest_files.each_with_index do |file, idx|
|
286
|
-
UI.
|
287
|
+
UI.start_processing_file(file, idx, @file_resolver.manifest_files.count)
|
287
288
|
process_file(file)
|
288
289
|
end
|
289
290
|
|
290
|
-
UI.
|
291
|
+
UI.end_processing
|
291
292
|
end
|
292
293
|
|
293
294
|
# @param [Epuber::Book::TocItem] toc_item
|
@@ -305,11 +306,13 @@ module Epuber
|
|
305
306
|
end
|
306
307
|
|
307
308
|
def process_global_ids
|
308
|
-
|
309
|
-
|
309
|
+
UI.print_step_processing_time('Processing global ids') do
|
310
|
+
xhtml_files = @file_resolver.files.select { |file| file.is_a?(FileTypes::XHTMLFile) }
|
311
|
+
global_ids = validate_global_ids(xhtml_files)
|
310
312
|
|
311
|
-
|
312
|
-
|
313
|
+
xhtml_files.each do |file|
|
314
|
+
file.process_global_ids(compilation_context, global_ids)
|
315
|
+
end
|
313
316
|
end
|
314
317
|
end
|
315
318
|
|
data/lib/epuber/config.rb
CHANGED
@@ -8,10 +8,13 @@ module Epuber
|
|
8
8
|
class Config
|
9
9
|
WORKING_PATH = '.epuber'
|
10
10
|
|
11
|
-
# @return [String]
|
11
|
+
# @return [String] path to project directory (where .bookspec file is located or current directory if not found)
|
12
12
|
#
|
13
13
|
def project_path
|
14
|
-
@project_path ||=
|
14
|
+
@project_path ||= begin
|
15
|
+
path = self.class.find_project_dir(Dir.pwd) || Dir.pwd
|
16
|
+
path.unicode_normalize
|
17
|
+
end
|
15
18
|
end
|
16
19
|
|
17
20
|
# @param [String] of_file absolute path to file
|
@@ -19,7 +22,9 @@ module Epuber
|
|
19
22
|
# @return [String] relative path to file from root of project
|
20
23
|
#
|
21
24
|
def pretty_path_from_project(of_file)
|
22
|
-
Pathname.new(of_file.unicode_normalize)
|
25
|
+
Pathname.new(of_file.unicode_normalize)
|
26
|
+
.relative_path_from(Pathname.new(project_path))
|
27
|
+
.to_s
|
23
28
|
end
|
24
29
|
|
25
30
|
# @return [String]
|
@@ -31,7 +36,7 @@ module Epuber
|
|
31
36
|
# @return [String]
|
32
37
|
#
|
33
38
|
def bookspec_path
|
34
|
-
@bookspec_path ||=
|
39
|
+
@bookspec_path ||= self.class.find_bookspec_files(project_path).first
|
35
40
|
end
|
36
41
|
|
37
42
|
# @return [String]
|
@@ -40,16 +45,6 @@ module Epuber
|
|
40
45
|
"#{bookspec_path}.lock"
|
41
46
|
end
|
42
47
|
|
43
|
-
# @return [Array<String>]
|
44
|
-
#
|
45
|
-
def find_all_bookspecs
|
46
|
-
Dir.chdir(project_path) do
|
47
|
-
Dir.glob('*.bookspec').map do |path|
|
48
|
-
File.expand_path(path)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
48
|
# @return [Epuber::Book]
|
54
49
|
#
|
55
50
|
def bookspec
|
@@ -182,6 +177,32 @@ module Epuber
|
|
182
177
|
|
183
178
|
book
|
184
179
|
end
|
180
|
+
|
181
|
+
# Find all bookspec files in given directory
|
182
|
+
#
|
183
|
+
# @param [String] dir
|
184
|
+
#
|
185
|
+
def find_bookspec_files(dir)
|
186
|
+
Dir.chdir(dir) do
|
187
|
+
Dir.glob('*.bookspec').map do |path|
|
188
|
+
File.expand_path(path)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Find project directory by searching for .bookspec files in current and parent directories
|
194
|
+
#
|
195
|
+
# @param [String] dir
|
196
|
+
# @return [String, nil]
|
197
|
+
#
|
198
|
+
def find_project_dir(dir)
|
199
|
+
return dir if find_bookspec_files(dir).any?
|
200
|
+
|
201
|
+
parent = File.dirname(dir)
|
202
|
+
return nil if parent == dir
|
203
|
+
|
204
|
+
find_project_dir(parent)
|
205
|
+
end
|
185
206
|
end
|
186
207
|
|
187
208
|
self.test = false
|
data/lib/epuber/epubcheck.rb
CHANGED
@@ -1,14 +1,94 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'open3'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
require_relative 'utils/location'
|
7
|
+
|
3
8
|
module Epuber
|
4
9
|
class Epubcheck
|
10
|
+
Report = Struct.new(:problems, keyword_init: true) do
|
11
|
+
# !attribute [r] problems
|
12
|
+
# @return [Array<Problem>] problems found by epubcheck
|
13
|
+
|
14
|
+
def error?
|
15
|
+
problems.any?(&:error?)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Problem = Struct.new(:level, :code, :location, :message, keyword_init: true) do
|
20
|
+
# !attribute [r] level
|
21
|
+
# @return [Symbol] level of the problem (:fatal, :error, :warning, :info, :usage, :suppressed)
|
22
|
+
|
23
|
+
# !attribute [r] code
|
24
|
+
# @return [String] code of the problem (for example: RSC-005)
|
25
|
+
|
26
|
+
# !attribute [r] location
|
27
|
+
# @return [Epuber::Location, nil] location of the problem
|
28
|
+
|
29
|
+
# !attribute [r] message
|
30
|
+
# @return [String] message of the problem
|
31
|
+
|
32
|
+
def to_s
|
33
|
+
"#{level}(#{code}): #{location.path}(#{location.lineno},#{location.column}): #{message}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def error?
|
37
|
+
level == :error || level == :fatal
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.from_json(json)
|
41
|
+
json_location = json['locations'].first
|
42
|
+
|
43
|
+
location = if json_location
|
44
|
+
Epuber::Location.new(
|
45
|
+
path: json_location['path'],
|
46
|
+
lineno: json_location['line'],
|
47
|
+
column: json_location['column'],
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
new(
|
52
|
+
level: json['severity'].downcase.to_sym,
|
53
|
+
code: json['ID'],
|
54
|
+
message: json['message'],
|
55
|
+
location: location,
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
5
60
|
class << self
|
6
61
|
# @param [String] path path to file
|
7
62
|
#
|
63
|
+
# @return [Report] report of the epubcheck
|
64
|
+
#
|
8
65
|
def check(path)
|
9
|
-
|
66
|
+
report = nil
|
67
|
+
|
68
|
+
Dir.mktmpdir('epubcheck-') do |tmpdir|
|
69
|
+
json_path = File.join(tmpdir, 'epubcheck.json')
|
70
|
+
Open3.popen3('epubcheck', path, '--json', json_path) do |_stdin, _stdout, stderr, wait_thr|
|
71
|
+
exit_status = wait_thr.value
|
72
|
+
|
73
|
+
if exit_status.success?
|
74
|
+
report = _parse_json(File.read(json_path))
|
75
|
+
else
|
76
|
+
UI.error(stderr.gets.chomp)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
report
|
82
|
+
end
|
83
|
+
|
84
|
+
# @param [String] string json string
|
85
|
+
# @return [Report]
|
86
|
+
#
|
87
|
+
def _parse_json(string)
|
88
|
+
json = JSON.parse(string)
|
89
|
+
messages = json['messages']
|
10
90
|
|
11
|
-
|
91
|
+
Report.new(problems: messages.map { |msg| Problem.from_json(msg) })
|
12
92
|
end
|
13
93
|
end
|
14
94
|
end
|