epuber 0.3.5
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 +7 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +46 -0
- data/bin/epuber +10 -0
- data/epuber.gemspec +51 -0
- data/lib/epuber.rb +14 -0
- data/lib/epuber/book.rb +267 -0
- data/lib/epuber/book/contributor.rb +90 -0
- data/lib/epuber/book/file_request.rb +68 -0
- data/lib/epuber/book/target.rb +284 -0
- data/lib/epuber/book/toc_item.rb +130 -0
- data/lib/epuber/checker.rb +19 -0
- data/lib/epuber/checker/text_checker.rb +129 -0
- data/lib/epuber/checker_transformer_base.rb +71 -0
- data/lib/epuber/command.rb +65 -0
- data/lib/epuber/command/compile.rb +142 -0
- data/lib/epuber/command/init.rb +145 -0
- data/lib/epuber/command/server.rb +59 -0
- data/lib/epuber/compiler.rb +255 -0
- data/lib/epuber/compiler/compilation_context.rb +86 -0
- data/lib/epuber/compiler/file_finders/abstract.rb +270 -0
- data/lib/epuber/compiler/file_finders/imaginary.rb +167 -0
- data/lib/epuber/compiler/file_finders/normal.rb +22 -0
- data/lib/epuber/compiler/file_resolver.rb +316 -0
- data/lib/epuber/compiler/file_types/abstract_file.rb +119 -0
- data/lib/epuber/compiler/file_types/bade_file.rb +39 -0
- data/lib/epuber/compiler/file_types/container_xml_file.rb +26 -0
- data/lib/epuber/compiler/file_types/generated_file.rb +29 -0
- data/lib/epuber/compiler/file_types/ibooks_display_options_file.rb +31 -0
- data/lib/epuber/compiler/file_types/image_file.rb +42 -0
- data/lib/epuber/compiler/file_types/mime_type_file.rb +20 -0
- data/lib/epuber/compiler/file_types/nav_file.rb +42 -0
- data/lib/epuber/compiler/file_types/opf_file.rb +27 -0
- data/lib/epuber/compiler/file_types/source_file.rb +52 -0
- data/lib/epuber/compiler/file_types/static_file.rb +18 -0
- data/lib/epuber/compiler/file_types/stylus_file.rb +20 -0
- data/lib/epuber/compiler/file_types/xhtml_file.rb +102 -0
- data/lib/epuber/compiler/generator.rb +67 -0
- data/lib/epuber/compiler/meta_inf_generator.rb +41 -0
- data/lib/epuber/compiler/nav_generator.rb +201 -0
- data/lib/epuber/compiler/opf_generator.rb +284 -0
- data/lib/epuber/compiler/xhtml_processor.rb +254 -0
- data/lib/epuber/config.rb +133 -0
- data/lib/epuber/dsl/attribute.rb +248 -0
- data/lib/epuber/dsl/attribute_support.rb +130 -0
- data/lib/epuber/dsl/object.rb +145 -0
- data/lib/epuber/dsl/tree_object.rb +101 -0
- data/lib/epuber/helper.rb +19 -0
- data/lib/epuber/lockfile.rb +55 -0
- data/lib/epuber/plugin.rb +108 -0
- data/lib/epuber/ruby_extensions/match_data.rb +40 -0
- data/lib/epuber/ruby_extensions/thread.rb +13 -0
- data/lib/epuber/server.rb +614 -0
- data/lib/epuber/server/auto_refresh/auto_refresh.coffee +97 -0
- data/lib/epuber/server/auto_refresh/connector.coffee +125 -0
- data/lib/epuber/server/auto_refresh/protocol.coffee +41 -0
- data/lib/epuber/server/auto_refresh/reloader.coffee +261 -0
- data/lib/epuber/server/base.styl +3 -0
- data/lib/epuber/server/basic.styl +211 -0
- data/lib/epuber/server/book_content.styl +39 -0
- data/lib/epuber/server/default_cover.png +0 -0
- data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Bold.ttf +0 -0
- data/lib/epuber/server/fonts/AvenirNext/AvenirNext-BoldItalic.ttf +0 -0
- data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Italic.ttf +0 -0
- data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Regular.ttf +0 -0
- data/lib/epuber/server/handlers.rb +67 -0
- data/lib/epuber/server/keyboard_control.coffee +6 -0
- data/lib/epuber/server/pages/book.bade +75 -0
- data/lib/epuber/server/pages/common.bade +59 -0
- data/lib/epuber/server/pages/files.bade +17 -0
- data/lib/epuber/server/pages/toc.bade +29 -0
- data/lib/epuber/server/support.coffee +10 -0
- data/lib/epuber/templates/template.bookspec +143 -0
- data/lib/epuber/third_party/bower.rb +22 -0
- data/lib/epuber/third_party/bower/bower.json +10 -0
- data/lib/epuber/third_party/bower/bower_components/cookies-js/bower.json +10 -0
- data/lib/epuber/third_party/bower/bower_components/cookies-js/dist/cookies.d.ts +33 -0
- data/lib/epuber/third_party/bower/bower_components/cookies-js/dist/cookies.js +173 -0
- data/lib/epuber/third_party/bower/bower_components/cookies-js/dist/cookies.min.js +6 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/MIT-LICENSE.txt +21 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/bower.json +28 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/dist/jquery.js +9210 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/dist/jquery.min.js +5 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/dist/jquery.min.map +1 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax.js +786 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/jsonp.js +89 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/load.js +75 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/parseJSON.js +13 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/parseXML.js +28 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/script.js +64 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/var/nonce.js +5 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/var/rquery.js +3 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/xhr.js +136 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/attributes.js +11 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/attributes/attr.js +141 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/attributes/classes.js +158 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/attributes/prop.js +94 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/attributes/support.js +35 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/attributes/val.js +161 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/callbacks.js +205 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/core.js +502 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/core/access.js +60 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/core/init.js +123 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/core/parseHTML.js +39 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/core/ready.js +97 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/core/var/rsingleTag.js +4 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/css.js +450 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/css/addGetHookIf.js +22 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/css/curCSS.js +57 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/css/defaultDisplay.js +70 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/css/hiddenVisibleSelectors.js +15 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/css/support.js +96 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/css/swap.js +28 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/css/var/cssExpand.js +3 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/css/var/getStyles.js +12 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/css/var/isHidden.js +13 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/css/var/rmargin.js +3 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/css/var/rnumnonpx.js +5 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/data.js +178 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/data/Data.js +181 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/data/accepts.js +20 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/data/var/data_priv.js +5 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/data/var/data_user.js +5 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/deferred.js +149 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/deprecated.js +13 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/dimensions.js +50 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/effects.js +648 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/effects/Tween.js +114 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/effects/animatedSelector.js +13 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/event.js +868 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/event/ajax.js +13 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/event/alias.js +39 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/event/support.js +9 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/exports/amd.js +24 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/exports/global.js +32 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/intro.js +44 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/jquery.js +37 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/manipulation.js +580 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/manipulation/_evalUrl.js +18 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/manipulation/support.js +32 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/manipulation/var/rcheckableType.js +3 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/offset.js +207 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/outro.js +1 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/queue.js +142 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/queue/delay.js +22 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/selector-native.js +172 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/selector-sizzle.js +14 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/selector.js +1 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/serialize.js +111 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/sizzle/dist/sizzle.js +2067 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/sizzle/dist/sizzle.min.js +3 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/sizzle/dist/sizzle.min.map +1 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/traversing.js +199 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/traversing/findFilter.js +100 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/traversing/var/rneedsContext.js +6 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/var/arr.js +3 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/var/class2type.js +4 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/var/concat.js +5 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/var/hasOwn.js +5 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/var/indexOf.js +5 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/var/pnum.js +3 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/var/push.js +5 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/var/rnotwhite.js +3 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/var/slice.js +5 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/var/strundefined.js +3 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/var/support.js +4 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/var/toString.js +5 -0
- data/lib/epuber/third_party/bower/bower_components/jquery/src/wrap.js +79 -0
- data/lib/epuber/third_party/bower/bower_components/keymaster/MIT-LICENSE +20 -0
- data/lib/epuber/third_party/bower/bower_components/keymaster/Makefile +4 -0
- data/lib/epuber/third_party/bower/bower_components/keymaster/README.markdown +212 -0
- data/lib/epuber/third_party/bower/bower_components/keymaster/bower.json +27 -0
- data/lib/epuber/third_party/bower/bower_components/keymaster/keymaster.js +296 -0
- data/lib/epuber/third_party/bower/bower_components/keymaster/package.json +11 -0
- data/lib/epuber/third_party/bower/bower_components/keymaster/test.html +93 -0
- data/lib/epuber/third_party/bower/bower_components/spin.js/LICENSE.txt +21 -0
- data/lib/epuber/third_party/bower/bower_components/spin.js/README.md +21 -0
- data/lib/epuber/third_party/bower/bower_components/spin.js/bower.json +18 -0
- data/lib/epuber/third_party/bower/bower_components/spin.js/jquery.spin.js +80 -0
- data/lib/epuber/third_party/bower/bower_components/spin.js/spin.js +337 -0
- data/lib/epuber/third_party/bower/bower_components/uri.js/LICENSE.txt +21 -0
- data/lib/epuber/third_party/bower/bower_components/uri.js/README.md +534 -0
- data/lib/epuber/third_party/bower/bower_components/uri.js/bower.json +16 -0
- data/lib/epuber/third_party/bower/bower_components/uri.js/contributing.md +19 -0
- data/lib/epuber/third_party/bower/bower_components/uri.js/src/IPv6.js +188 -0
- data/lib/epuber/third_party/bower/bower_components/uri.js/src/SecondLevelDomains.js +241 -0
- data/lib/epuber/third_party/bower/bower_components/uri.js/src/URI.fragmentQuery.js +104 -0
- data/lib/epuber/third_party/bower/bower_components/uri.js/src/URI.fragmentURI.js +97 -0
- data/lib/epuber/third_party/bower/bower_components/uri.js/src/URI.js +2115 -0
- data/lib/epuber/third_party/bower/bower_components/uri.js/src/URI.min.js +86 -0
- data/lib/epuber/third_party/bower/bower_components/uri.js/src/URITemplate.js +499 -0
- data/lib/epuber/third_party/bower/bower_components/uri.js/src/jquery.URI.js +235 -0
- data/lib/epuber/third_party/bower/bower_components/uri.js/src/jquery.URI.min.js +7 -0
- data/lib/epuber/third_party/bower/bower_components/uri.js/src/punycode.js +508 -0
- data/lib/epuber/transformer.rb +19 -0
- data/lib/epuber/transformer/text_transformer.rb +60 -0
- data/lib/epuber/user_interface.rb +186 -0
- data/lib/epuber/vendor/globals_context.rb +26 -0
- data/lib/epuber/vendor/hash_binding.rb +26 -0
- data/lib/epuber/vendor/nokogiri_extensions.rb +30 -0
- data/lib/epuber/vendor/ruby_templater.rb +71 -0
- data/lib/epuber/vendor/size.rb +20 -0
- data/lib/epuber/vendor/version.rb +83 -0
- data/lib/epuber/version.rb +4 -0
- metadata +556 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require_relative '../command'
|
4
|
+
require 'os'
|
5
|
+
|
6
|
+
|
7
|
+
module Epuber
|
8
|
+
class Command
|
9
|
+
class Server < Command
|
10
|
+
self.summary = 'Starts web server to display and debug e-book pages.'
|
11
|
+
self.arguments = [
|
12
|
+
CLAide::Argument.new('TARGET', false, false),
|
13
|
+
]
|
14
|
+
|
15
|
+
def self.options
|
16
|
+
[
|
17
|
+
['--open', 'Opens the web page in default web browser, working only on OS X'],
|
18
|
+
].concat(super)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param args [CLAide::ARGV]
|
22
|
+
#
|
23
|
+
def initialize(args)
|
24
|
+
super
|
25
|
+
@selected_target_name = args.shift_argument
|
26
|
+
@open_web_browser = args.flag?('open', false)
|
27
|
+
end
|
28
|
+
|
29
|
+
def validate!
|
30
|
+
super
|
31
|
+
verify_one_bookspec_exists!
|
32
|
+
end
|
33
|
+
|
34
|
+
def run
|
35
|
+
super
|
36
|
+
|
37
|
+
require_relative '../server'
|
38
|
+
|
39
|
+
target = if @selected_target_name.nil?
|
40
|
+
book.targets.first
|
41
|
+
else
|
42
|
+
book.target_named(@selected_target_name)
|
43
|
+
end
|
44
|
+
|
45
|
+
help!('Not existing target') if target.nil?
|
46
|
+
|
47
|
+
Epuber::Server.run!(book, target, verbose: verbose?) do |uri|
|
48
|
+
if OS.osx?
|
49
|
+
if @open_web_browser
|
50
|
+
system "open #{uri}"
|
51
|
+
else
|
52
|
+
puts 'Web browser can be automatically opened by adding --open flag, see --help'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,255 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'English'
|
4
|
+
|
5
|
+
require 'pathname'
|
6
|
+
require 'fileutils'
|
7
|
+
|
8
|
+
require 'zip'
|
9
|
+
|
10
|
+
require_relative 'vendor/nokogiri_extensions'
|
11
|
+
require_relative 'vendor/globals_context'
|
12
|
+
|
13
|
+
require_relative 'plugin'
|
14
|
+
|
15
|
+
|
16
|
+
module Epuber
|
17
|
+
class Compiler
|
18
|
+
require_relative 'compiler/compilation_context'
|
19
|
+
|
20
|
+
require_relative 'compiler/opf_generator'
|
21
|
+
require_relative 'compiler/nav_generator'
|
22
|
+
require_relative 'compiler/meta_inf_generator'
|
23
|
+
|
24
|
+
require_relative 'compiler/file_resolver'
|
25
|
+
require_relative 'compiler/file_finders/normal'
|
26
|
+
|
27
|
+
|
28
|
+
EPUB_CONTENT_FOLDER = 'OEBPS'
|
29
|
+
|
30
|
+
# @return [Epuber::GlobalsContext]
|
31
|
+
#
|
32
|
+
def self.globals_catcher
|
33
|
+
@globals_catcher ||= Epuber::GlobalsContext.new
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [Epuber::Compiler::FileResolver]
|
37
|
+
#
|
38
|
+
attr_reader :file_resolver
|
39
|
+
|
40
|
+
# @return [CompilationContext]
|
41
|
+
#
|
42
|
+
attr_reader :compilation_context
|
43
|
+
|
44
|
+
# @param book [Epuber::Book::Book]
|
45
|
+
# @param target [Epuber::Book::Target]
|
46
|
+
#
|
47
|
+
def initialize(book, target)
|
48
|
+
@book = book
|
49
|
+
@target = target
|
50
|
+
@compilation_context = CompilationContext.new(book, target)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Compile target to build folder
|
54
|
+
#
|
55
|
+
# @param build_folder [String] path to folder, where will be stored all compiled files
|
56
|
+
# @param [Bool] check should run non-release checkers
|
57
|
+
# @param [Bool] write should perform transformations of source files and write them back
|
58
|
+
# @param [Bool] release this is release build
|
59
|
+
#
|
60
|
+
# @return [void]
|
61
|
+
#
|
62
|
+
def compile(build_folder, check: false, write: false, release: false, verbose: false)
|
63
|
+
@file_resolver = FileResolver.new(Config.instance.project_path, build_folder)
|
64
|
+
compilation_context.file_resolver = @file_resolver
|
65
|
+
compilation_context.should_check = check
|
66
|
+
compilation_context.should_write = write
|
67
|
+
compilation_context.release_build = release
|
68
|
+
compilation_context.verbose = verbose
|
69
|
+
|
70
|
+
self.class.globals_catcher.catch do
|
71
|
+
@build_folder = build_folder
|
72
|
+
|
73
|
+
FileUtils.mkdir_p(build_folder)
|
74
|
+
|
75
|
+
puts " handling target #{@target.name.inspect} in build dir `#{Config.instance.pretty_path_from_project(build_folder)}`"
|
76
|
+
|
77
|
+
parse_toc_item(@target.root_toc)
|
78
|
+
parse_target_file_requests
|
79
|
+
|
80
|
+
process_all_target_files
|
81
|
+
generate_other_files
|
82
|
+
|
83
|
+
# build folder cleanup
|
84
|
+
remove_unnecessary_files
|
85
|
+
remove_empty_folders
|
86
|
+
end
|
87
|
+
ensure
|
88
|
+
self.class.globals_catcher.clear_all
|
89
|
+
end
|
90
|
+
|
91
|
+
# Archives current target files to epub
|
92
|
+
#
|
93
|
+
# @param path [String] path to created archive
|
94
|
+
#
|
95
|
+
# @return [String] path
|
96
|
+
#
|
97
|
+
def archive(path = nil, configuration_suffix: nil)
|
98
|
+
path ||= epub_name(configuration_suffix)
|
99
|
+
|
100
|
+
epub_path = File.expand_path(path)
|
101
|
+
|
102
|
+
Dir.chdir(@file_resolver.destination_path) do
|
103
|
+
new_paths = @file_resolver.package_files.map(&:pkg_destination_path)
|
104
|
+
|
105
|
+
if ::File.exists?(epub_path)
|
106
|
+
Zip::File.open(epub_path, true) do |zip_file|
|
107
|
+
old_paths = zip_file.instance_eval { @entry_set.entries.map(&:name) }
|
108
|
+
diff = old_paths - new_paths
|
109
|
+
diff.each do |file_to_remove|
|
110
|
+
puts "DEBUG: removing file from result EPUB: #{file_to_remove}" if compilation_context.verbose?
|
111
|
+
zip_file.remove(file_to_remove)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
run_command(%(zip -q0X "#{epub_path}" mimetype))
|
117
|
+
run_command(%(zip -qXr9D "#{epub_path}" "#{new_paths.join('" "')}" --exclude \\*.DS_Store))
|
118
|
+
end
|
119
|
+
|
120
|
+
path
|
121
|
+
end
|
122
|
+
|
123
|
+
# Creates name of epub file for current book and current target
|
124
|
+
#
|
125
|
+
# @return [String] name of result epub file
|
126
|
+
#
|
127
|
+
def epub_name(configuration_suffix = nil)
|
128
|
+
epub_name = if !@book.output_base_name.nil?
|
129
|
+
@book.output_base_name
|
130
|
+
elsif @book.from_file?
|
131
|
+
::File.basename(@book.file_path, ::File.extname(@book.file_path))
|
132
|
+
else
|
133
|
+
@book.title
|
134
|
+
end
|
135
|
+
|
136
|
+
epub_name += @book.build_version.to_s unless @book.build_version.nil?
|
137
|
+
epub_name += "-#{@target.name}" if @target != @book.default_target
|
138
|
+
epub_name += "-#{configuration_suffix}" unless configuration_suffix.nil?
|
139
|
+
epub_name + '.epub'
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
# @return nil
|
146
|
+
#
|
147
|
+
def remove_empty_folders
|
148
|
+
Dir.chdir(@file_resolver.destination_path) do
|
149
|
+
Dir.glob('**/*')
|
150
|
+
.select { |d| File.directory?(d) }
|
151
|
+
.select { |d| (Dir.entries(d) - %w(. ..)).empty? }
|
152
|
+
.each do |d|
|
153
|
+
puts "DEBUG: removing empty folder `#{d}`" if compilation_context.verbose?
|
154
|
+
Dir.rmdir(d)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# @return nil
|
160
|
+
#
|
161
|
+
def remove_unnecessary_files
|
162
|
+
unnecessary_paths = @file_resolver.unneeded_files_in_destination.map { |path| File.join(@file_resolver.destination_path, path) }
|
163
|
+
unnecessary_paths.each do |path|
|
164
|
+
puts "DEBUG: removing unnecessary file: `#{Config.instance.pretty_path_from_project(path)}`" if compilation_context.verbose?
|
165
|
+
|
166
|
+
File.delete(path)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# @return nil
|
171
|
+
#
|
172
|
+
def generate_other_files
|
173
|
+
# generate nav file (nav.xhtml or nav.ncx)
|
174
|
+
nav_file = FileTypes::NavFile.new(@target.epub_version)
|
175
|
+
@file_resolver.add_file(nav_file)
|
176
|
+
process_file(nav_file)
|
177
|
+
|
178
|
+
# generate .opf file
|
179
|
+
opf_file = FileTypes::OPFFile.new
|
180
|
+
@file_resolver.add_file(opf_file)
|
181
|
+
process_file(opf_file)
|
182
|
+
|
183
|
+
# generate mimetype file
|
184
|
+
mimetype_file = FileTypes::MimeTypeFile.new
|
185
|
+
@file_resolver.add_file(mimetype_file)
|
186
|
+
process_file(mimetype_file)
|
187
|
+
|
188
|
+
# generate META-INF files
|
189
|
+
container_xml = FileTypes::ContainerXMLFile.new
|
190
|
+
@file_resolver.add_file(container_xml)
|
191
|
+
process_file(container_xml)
|
192
|
+
|
193
|
+
if @target.epub_version >= 2.0 && @target.epub_version < 3.0
|
194
|
+
ibooks_options = FileTypes::IBooksDisplayOptionsFile.new
|
195
|
+
@file_resolver.add_file(ibooks_options)
|
196
|
+
process_file(ibooks_options)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# @return nil
|
201
|
+
#
|
202
|
+
def parse_target_file_requests
|
203
|
+
@target.files.each do |file_request|
|
204
|
+
@file_resolver.add_file_from_request(file_request)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# @param [FileTypes::AbstractFile] file
|
209
|
+
#
|
210
|
+
def process_file(file)
|
211
|
+
file.process(compilation_context)
|
212
|
+
end
|
213
|
+
|
214
|
+
# @return nil
|
215
|
+
#
|
216
|
+
def process_all_target_files
|
217
|
+
@file_resolver.manifest_files.each_with_index do |file, idx|
|
218
|
+
UI.print_processing_file(file, idx, @file_resolver.manifest_files.count)
|
219
|
+
process_file(file)
|
220
|
+
end
|
221
|
+
|
222
|
+
UI.processing_files_done
|
223
|
+
end
|
224
|
+
|
225
|
+
# @param toc_item [Epuber::Book::TocItem]
|
226
|
+
#
|
227
|
+
def parse_toc_item(toc_item)
|
228
|
+
unless toc_item.file_request.nil?
|
229
|
+
file = @file_resolver.add_file_from_request(toc_item.file_request, :spine)
|
230
|
+
file.toc_item = toc_item if file.toc_item.nil?
|
231
|
+
end
|
232
|
+
|
233
|
+
# process recursively other files
|
234
|
+
toc_item.sub_items.each do |child|
|
235
|
+
parse_toc_item(child)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
# @param cmd [String]
|
240
|
+
#
|
241
|
+
# @return [void]
|
242
|
+
#
|
243
|
+
# @raise if the return value is not 0
|
244
|
+
#
|
245
|
+
def run_command(cmd)
|
246
|
+
system(cmd)
|
247
|
+
|
248
|
+
$stdout.flush
|
249
|
+
$stderr.flush
|
250
|
+
|
251
|
+
code = $CHILD_STATUS
|
252
|
+
raise 'wrong return value' if code != 0
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
|
4
|
+
module Epuber
|
5
|
+
class Compiler
|
6
|
+
class CompilationContext
|
7
|
+
# @return [Epuber::Book]
|
8
|
+
#
|
9
|
+
attr_reader :book
|
10
|
+
|
11
|
+
# @return [Epuber::Book::Target]
|
12
|
+
#
|
13
|
+
attr_reader :target
|
14
|
+
|
15
|
+
# @return [Epuber::Compiler::FileResolver]
|
16
|
+
#
|
17
|
+
attr_accessor :file_resolver
|
18
|
+
|
19
|
+
# @return [Array<Epuber::Plugin>]
|
20
|
+
#
|
21
|
+
def plugins
|
22
|
+
@plugins ||= @target.plugins.map do |path|
|
23
|
+
begin
|
24
|
+
plugin = Plugin.new(File.expand_path(path, Config.instance.project_path))
|
25
|
+
plugin.files.each do |file|
|
26
|
+
file_resolver.add_file(file)
|
27
|
+
end
|
28
|
+
plugin
|
29
|
+
rescue LoadError
|
30
|
+
UI.error "Can't find plugin at path #{path}"
|
31
|
+
end
|
32
|
+
end.compact
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param [Class] klass class of thing you want to perform (Checker or Transformer)
|
36
|
+
# @param [Symbol] source_type source type of that thing (Checker or Transformer)
|
37
|
+
#
|
38
|
+
# @yield
|
39
|
+
# @yieldparam [Epuber::CheckerTransformerBase] instance of checker or transformer
|
40
|
+
#
|
41
|
+
# @return nil
|
42
|
+
#
|
43
|
+
def perform_plugin_things(klass, source_type)
|
44
|
+
plugins.each do |plugin|
|
45
|
+
plugin.instances(klass).each do |instance|
|
46
|
+
# @type [Epuber::CheckerTransformerBase] instance
|
47
|
+
|
48
|
+
next if instance.source_type != source_type
|
49
|
+
next if instance.options.include?(:run_only_before_release) && !release_build
|
50
|
+
|
51
|
+
yield instance
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
#########
|
58
|
+
|
59
|
+
# @return [Bool]
|
60
|
+
#
|
61
|
+
attr_accessor :should_check
|
62
|
+
|
63
|
+
# @return [Bool]
|
64
|
+
#
|
65
|
+
attr_accessor :should_write
|
66
|
+
|
67
|
+
# @return [Bool]
|
68
|
+
#
|
69
|
+
attr_accessor :release_build
|
70
|
+
|
71
|
+
# @return [Bool]
|
72
|
+
#
|
73
|
+
attr_accessor :verbose
|
74
|
+
|
75
|
+
def verbose?
|
76
|
+
verbose
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def initialize(book, target)
|
81
|
+
@book = book
|
82
|
+
@target = target
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,270 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'unicode_normalize'
|
4
|
+
|
5
|
+
|
6
|
+
module Epuber
|
7
|
+
class Compiler
|
8
|
+
module FileFinders
|
9
|
+
class FileNotFoundError < ::StandardError
|
10
|
+
# @return [String]
|
11
|
+
#
|
12
|
+
attr_reader :pattern
|
13
|
+
|
14
|
+
# @return [String]
|
15
|
+
#
|
16
|
+
attr_reader :context_path
|
17
|
+
|
18
|
+
# @param [String] pattern
|
19
|
+
# @param [String] context_path
|
20
|
+
#
|
21
|
+
def initialize(pattern, context_path)
|
22
|
+
@pattern = pattern
|
23
|
+
@context_path = context_path
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
"Not found file matching pattern `#{pattern}` from context path #{context_path}."
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class MultipleFilesFoundError < ::StandardError
|
32
|
+
# @return [Array<String>]
|
33
|
+
#
|
34
|
+
attr_reader :files_paths
|
35
|
+
|
36
|
+
# @return [Array<Symbol>]
|
37
|
+
#
|
38
|
+
attr_reader :groups
|
39
|
+
|
40
|
+
# @return [String]
|
41
|
+
#
|
42
|
+
attr_reader :pattern
|
43
|
+
|
44
|
+
# @return [String]
|
45
|
+
#
|
46
|
+
attr_reader :context_path
|
47
|
+
|
48
|
+
# @param [String] pattern original pattern for searching
|
49
|
+
# @param [Symbol] groups list of groups
|
50
|
+
# @param [String] context_path context path of current searching
|
51
|
+
# @param [Array<String>] files_paths list of founded files
|
52
|
+
#
|
53
|
+
def initialize(pattern, groups, context_path, files_paths)
|
54
|
+
@pattern = pattern
|
55
|
+
@groups = groups
|
56
|
+
@context_path = context_path
|
57
|
+
@files_paths = files_paths
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_s
|
61
|
+
str = "Found too many files for pattern `#{pattern}` from context path #{context_path}"
|
62
|
+
str += ", file groups #{groups.map(:inspect)}" unless groups.nil?
|
63
|
+
str + ", founded files #{files_paths}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
BINARY_EXTENSIONS = %w(.png .jpeg .jpg .otf .ttf)
|
68
|
+
STATIC_EXTENSIONS = BINARY_EXTENSIONS + %w(.css .js)
|
69
|
+
|
70
|
+
GROUP_EXTENSIONS = {
|
71
|
+
text: %w(.xhtml .html .bade),
|
72
|
+
image: %w(.png .jpg .jpeg),
|
73
|
+
font: %w(.otf .ttf),
|
74
|
+
style: %w(.css .styl),
|
75
|
+
script: %w(.js),
|
76
|
+
}
|
77
|
+
|
78
|
+
EXTENSIONS_RENAME = {
|
79
|
+
'.styl' => '.css',
|
80
|
+
|
81
|
+
'.bade' => '.xhtml',
|
82
|
+
}
|
83
|
+
|
84
|
+
class Abstract
|
85
|
+
|
86
|
+
# @return [String] path where should look for source files
|
87
|
+
#
|
88
|
+
attr_reader :source_path
|
89
|
+
|
90
|
+
# @return [Array<String>]
|
91
|
+
#
|
92
|
+
attr_accessor :ignored_patterns
|
93
|
+
|
94
|
+
|
95
|
+
# @param [String] source_path
|
96
|
+
#
|
97
|
+
def initialize(source_path)
|
98
|
+
@source_path = source_path.unicode_normalize.freeze
|
99
|
+
@source_path_abs = ::File.expand_path(@source_path).unicode_normalize.freeze
|
100
|
+
@ignored_patterns = []
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
def assert_one_file(files, pattern: nil, groups: nil, context_path: nil)
|
105
|
+
raise FileNotFoundError.new(pattern, context_path) if files.empty?
|
106
|
+
raise MultipleFilesFoundError.new(pattern, groups, context_path, files) if files.count >= 2
|
107
|
+
end
|
108
|
+
|
109
|
+
# Method for finding file from context_path, if there is not matching file, it will continue to search from
|
110
|
+
# #source_path and after that it tries to search recursively from #source_path.
|
111
|
+
#
|
112
|
+
# When it founds too many (more than two) it will raise MultipleFilesFoundError
|
113
|
+
#
|
114
|
+
# @param [String] pattern pattern of the desired files
|
115
|
+
# @param [Symbol] groups list of group names, nil or empty array for all groups, for valid values see GROUP_EXTENSIONS
|
116
|
+
# @param [String] context_path path for root of searching, it is also defines start folder of relative path
|
117
|
+
#
|
118
|
+
# @return [Array<String>] list of founded files
|
119
|
+
#
|
120
|
+
def find_file(pattern, groups: nil, context_path: nil, search_everywhere: true)
|
121
|
+
files = find_files(pattern, groups: groups, context_path: context_path, search_everywhere: search_everywhere)
|
122
|
+
assert_one_file(files, pattern: pattern, groups: groups, context_path: context_path)
|
123
|
+
files.first
|
124
|
+
end
|
125
|
+
|
126
|
+
# Method for finding files from context_path, if there is not matching file, it will continue to search from
|
127
|
+
# #source_path and after that it tries to search recursively from #source_path.
|
128
|
+
#
|
129
|
+
# @param [String] pattern pattern of the desired files
|
130
|
+
# @param [Array<Symbol>] groups list of group names, nil or empty array for all groups, for valid values see GROUP_EXTENSIONS
|
131
|
+
# @param [String] context_path path for root of searching, it is also defines start folder of relative path
|
132
|
+
#
|
133
|
+
# @return [Array<String>] list of founded files
|
134
|
+
#
|
135
|
+
def find_files(pattern, groups: nil, context_path: nil, search_everywhere: true)
|
136
|
+
files = []
|
137
|
+
searching_path = context_path
|
138
|
+
|
139
|
+
unless searching_path.nil?
|
140
|
+
searching_path = ::File.expand_path(context_path, @source_path_abs)
|
141
|
+
|
142
|
+
unless searching_path.start_with?(@source_path_abs)
|
143
|
+
raise "You can't search from folder (#{searching_path}) that is not sub folder of the source_path (#{source_path}) expanded to (#{@source_path_abs})."
|
144
|
+
end
|
145
|
+
|
146
|
+
files = __find_files(pattern, groups, searching_path)
|
147
|
+
end
|
148
|
+
|
149
|
+
if files.empty? && context_path != source_path
|
150
|
+
files = __find_files(pattern, groups, @source_path_abs, searching_path || @source_path_abs)
|
151
|
+
end
|
152
|
+
|
153
|
+
if files.empty? && search_everywhere && !pattern.start_with?('**')
|
154
|
+
files = __find_files('**/' + pattern, groups, @source_path_abs, searching_path || @source_path_abs)
|
155
|
+
end
|
156
|
+
|
157
|
+
files
|
158
|
+
end
|
159
|
+
|
160
|
+
# Looks for all files from #source_path recursively
|
161
|
+
#
|
162
|
+
# @param [String] pattern pattern of the desired files
|
163
|
+
# @param [Array<Symbol>] groups list of group names, nil or empty array for all groups, for valid values see GROUP_EXTENSIONS
|
164
|
+
# @param [String] context_path path for root of searching, it is also defines start folder of relative path
|
165
|
+
#
|
166
|
+
# @return [Array<String>] list of founded files
|
167
|
+
#
|
168
|
+
def find_all(pattern, groups: nil, context_path: @source_path_abs)
|
169
|
+
__find_files('**/' + pattern, groups, context_path)
|
170
|
+
end
|
171
|
+
|
172
|
+
# @param [Array<String>] paths list of file paths
|
173
|
+
# @param [Array<Symbol>] groups list of groups to filter file paths
|
174
|
+
#
|
175
|
+
# @return [Array<String>] filtered list of file paths
|
176
|
+
#
|
177
|
+
def self.group_filter_paths(paths, groups)
|
178
|
+
# filter depend on group
|
179
|
+
groups = Array(groups)
|
180
|
+
|
181
|
+
if groups.empty?
|
182
|
+
paths
|
183
|
+
else
|
184
|
+
valid_extensions = groups.map do |group|
|
185
|
+
GROUP_EXTENSIONS.fetch(group) { raise ::StandardError, "Unknown file group #{group.inspect}" }
|
186
|
+
end.flatten
|
187
|
+
|
188
|
+
paths.select do |file_path|
|
189
|
+
valid_extensions.include?(::File.extname(file_path))
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# @param [Array<String>] paths list of file paths
|
195
|
+
# @param [String] context_path
|
196
|
+
#
|
197
|
+
# @return [Array<String>] mapped list of file paths
|
198
|
+
#
|
199
|
+
def self.relative_paths_from(paths, context_path)
|
200
|
+
context_pathname = Pathname.new(context_path)
|
201
|
+
paths.map do |path|
|
202
|
+
Pathname(path.unicode_normalize).relative_path_from(context_pathname).to_s
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
private
|
207
|
+
|
208
|
+
# Looks for files at given context path, if there is no file, it will try again with pattern for any extension
|
209
|
+
#
|
210
|
+
# @param [String] pattern pattern of the desired files
|
211
|
+
# @param [Array<Symbol>] groups list of group names, nil or empty array for all groups, for valid values see GROUP_EXTENSIONS
|
212
|
+
# @param [String] context_path path for root of searching, it is also defines start folder of relative path
|
213
|
+
# @param [String] orig_context_path original context path, wo it will work nicely with iterative searching
|
214
|
+
#
|
215
|
+
# @return [Array<String>] list of founded files
|
216
|
+
#
|
217
|
+
def __find_files(pattern, groups, context_path, orig_context_path = context_path)
|
218
|
+
# remove fragment from pattern
|
219
|
+
pattern = pattern.sub(/#.*$/, '') if pattern.include?('#')
|
220
|
+
|
221
|
+
files = __core_find_files(pattern, groups, context_path, orig_context_path)
|
222
|
+
|
223
|
+
# try to find files with any extension
|
224
|
+
files = __core_find_files(pattern + '.*', groups, context_path, orig_context_path) if files.empty?
|
225
|
+
|
226
|
+
files
|
227
|
+
end
|
228
|
+
|
229
|
+
# Core method for finding files, it only search for files, filter by input groups and map the final paths to pretty relative paths from context_path
|
230
|
+
#
|
231
|
+
# @param [String] pattern pattern of the desired files
|
232
|
+
# @param [Array<Symbol>] groups list of group names, nil or empty array for all groups, for valid values see GROUP_EXTENSIONS
|
233
|
+
# @param [String] context_path path for root of searching, it is also defines start folder of relative path
|
234
|
+
# @param [String] orig_context_path original context path, wo it will work nicely with iterative searching
|
235
|
+
#
|
236
|
+
# @return [Array<String>] list of founded files
|
237
|
+
#
|
238
|
+
def __core_find_files(pattern, groups, context_path, orig_context_path = context_path)
|
239
|
+
context_path = __core_file?(context_path) ? File.dirname(context_path) : context_path
|
240
|
+
orig_context_path = __core_file?(orig_context_path) ? File.dirname(orig_context_path) : orig_context_path
|
241
|
+
|
242
|
+
full_pattern = File.expand_path(pattern, context_path)
|
243
|
+
file_paths = __core_find_files_from_pattern(full_pattern).map(&:unicode_normalize)
|
244
|
+
|
245
|
+
file_paths.reject! do |path|
|
246
|
+
File.directory?(path)
|
247
|
+
end
|
248
|
+
|
249
|
+
# remove any files that should be ignored
|
250
|
+
file_paths.reject! do |path|
|
251
|
+
ignored_patterns.any? { |exclude_pattern| File.fnmatch(exclude_pattern, path) }
|
252
|
+
end
|
253
|
+
|
254
|
+
file_paths = self.class.group_filter_paths(file_paths, groups)
|
255
|
+
|
256
|
+
# create relative path to context path
|
257
|
+
self.class.relative_paths_from(file_paths, orig_context_path)
|
258
|
+
end
|
259
|
+
|
260
|
+
def __core_find_files_from_pattern(pattern)
|
261
|
+
raise 'Implement this in subclass'
|
262
|
+
end
|
263
|
+
|
264
|
+
def __core_file?(path)
|
265
|
+
raise 'Implement this in subclass'
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|