webgen 1.0.0.beta3 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/COPYING +23 -1
- data/Rakefile +16 -77
- data/VERSION +1 -1
- data/bin/webgen +0 -0
- data/data/webgen/basic_website_template/ext/init.rb +3 -1
- data/data/webgen/basic_website_template/src/.gitignore +0 -0
- data/data/webgen/basic_website_template/webgen.config +1 -1
- data/data/webgen/bundle_template_files/info.yaml.erb +14 -2
- data/data/webgen/passive_sources/default.metainfo +10 -0
- data/data/webgen/passive_sources/templates/api.template +16 -2
- data/data/webgen/passive_sources/templates/feed.template +5 -5
- data/data/webgen/passive_sources/templates/sitemap.template +1 -1
- data/data/webgen/passive_sources/templates/tag.template +8 -4
- data/lib/webgen/blackboard.rb +21 -5
- data/lib/webgen/bundle/built-in-show-changes/info.yaml +17 -0
- data/lib/webgen/bundle/built-in-show-changes/init.rb +4 -5
- data/lib/webgen/bundle/built-in/info.yaml +1064 -0
- data/lib/webgen/bundle/built-in/init.rb +103 -136
- data/lib/webgen/bundle_loader.rb +82 -9
- data/lib/webgen/cli.rb +12 -8
- data/lib/webgen/cli/commands/create.rb +27 -0
- data/lib/webgen/cli/{create_bundle_command.rb → commands/create_bundle.rb} +2 -2
- data/lib/webgen/cli/{create_command.rb → commands/create_website.rb} +2 -2
- data/lib/webgen/cli/commands/generate.rb +66 -0
- data/lib/webgen/cli/{install_bundle_command.rb → commands/install.rb} +1 -1
- data/lib/webgen/cli/{show_command.rb → commands/show.rb} +6 -4
- data/lib/webgen/cli/{list_bundle_command.rb → commands/show_bundles.rb} +12 -15
- data/lib/webgen/cli/{show_config_command.rb → commands/show_config.rb} +34 -6
- data/lib/webgen/cli/{show_dependencies_command.rb → commands/show_dependencies.rb} +0 -0
- data/lib/webgen/cli/{show_extensions_command.rb → commands/show_extensions.rb} +1 -13
- data/lib/webgen/cli/{show_tree_command.rb → commands/show_tree.rb} +3 -0
- data/lib/webgen/cli/utils.rb +1 -1
- data/lib/webgen/configuration.rb +9 -11
- data/lib/webgen/content_processor/html_head.rb +3 -4
- data/lib/webgen/content_processor/rainpress.rb +21 -0
- data/lib/webgen/content_processor/sass.rb +8 -8
- data/lib/webgen/content_processor/tikz.rb +59 -16
- data/lib/webgen/item_tracker.rb +33 -12
- data/lib/webgen/item_tracker/missing_node.rb +5 -5
- data/lib/webgen/item_tracker/template_chain.rb +52 -0
- data/lib/webgen/misc/dummy_index.rb +78 -0
- data/lib/webgen/node.rb +1 -1
- data/lib/webgen/node_finder.rb +86 -141
- data/lib/webgen/page.rb +5 -5
- data/lib/webgen/path.rb +4 -1
- data/lib/webgen/path_handler.rb +25 -21
- data/lib/webgen/path_handler/api.rb +36 -3
- data/lib/webgen/path_handler/base.rb +20 -4
- data/lib/webgen/path_handler/feed.rb +6 -2
- data/lib/webgen/path_handler/meta_info.rb +4 -2
- data/lib/webgen/path_handler/page.rb +5 -7
- data/lib/webgen/path_handler/sitemap.rb +6 -1
- data/lib/webgen/path_handler/virtual.rb +6 -8
- data/lib/webgen/source/file_system.rb +2 -2
- data/lib/webgen/tag.rb +22 -18
- data/lib/webgen/tag/menu.rb +5 -5
- data/lib/webgen/test_helper.rb +18 -18
- data/lib/webgen/utils/external_command.rb +1 -1
- data/lib/webgen/utils/tag_parser.rb +1 -1
- data/lib/webgen/vendor/rainpress.rb +168 -0
- data/lib/webgen/version.rb +1 -1
- data/lib/webgen/website.rb +10 -10
- data/man/man1/webgen.1 +54 -23
- data/test/test_documentation.rb +27 -4
- data/test/webgen/cli/test_logger.rb +1 -1
- data/test/webgen/content_processor/test_blocks.rb +1 -1
- data/test/webgen/content_processor/test_builder.rb +3 -2
- data/test/webgen/content_processor/test_erb.rb +1 -1
- data/test/webgen/content_processor/test_erubis.rb +2 -2
- data/test/webgen/content_processor/test_fragments.rb +1 -1
- data/test/webgen/content_processor/test_haml.rb +2 -2
- data/test/webgen/content_processor/test_html_head.rb +5 -1
- data/test/webgen/content_processor/test_kramdown.rb +2 -2
- data/test/webgen/content_processor/test_maruku.rb +2 -2
- data/test/webgen/content_processor/test_r_discount.rb +2 -2
- data/test/webgen/content_processor/test_r_doc.rb +1 -1
- data/test/webgen/content_processor/test_rainpress.rb +19 -0
- data/test/webgen/content_processor/test_red_cloth.rb +2 -2
- data/test/webgen/content_processor/test_ruby.rb +1 -1
- data/test/webgen/content_processor/test_sass.rb +8 -6
- data/test/webgen/content_processor/test_scss.rb +3 -3
- data/test/webgen/content_processor/test_tags.rb +1 -1
- data/test/webgen/content_processor/test_tidy.rb +9 -1
- data/test/webgen/content_processor/test_tikz.rb +6 -3
- data/test/webgen/content_processor/test_xmllint.rb +9 -2
- data/test/webgen/destination/test_file_system.rb +4 -4
- data/test/webgen/item_tracker/test_file.rb +1 -1
- data/test/webgen/item_tracker/test_missing_node.rb +1 -1
- data/test/webgen/item_tracker/test_node_content.rb +1 -1
- data/test/webgen/item_tracker/test_node_meta_info.rb +1 -1
- data/test/webgen/item_tracker/test_nodes.rb +2 -4
- data/test/webgen/item_tracker/test_template_chain.rb +36 -0
- data/test/webgen/misc/test_dummy_index.rb +83 -0
- data/test/webgen/path_handler/test_api.rb +6 -46
- data/test/webgen/path_handler/test_base.rb +3 -2
- data/test/webgen/path_handler/test_copy.rb +1 -1
- data/test/webgen/path_handler/test_feed.rb +3 -4
- data/test/webgen/path_handler/test_meta_info.rb +1 -1
- data/test/webgen/path_handler/test_page.rb +1 -1
- data/test/webgen/path_handler/test_page_utils.rb +1 -1
- data/test/webgen/path_handler/test_sitemap.rb +3 -5
- data/test/webgen/path_handler/test_template.rb +1 -1
- data/test/webgen/path_handler/test_virtual.rb +1 -3
- data/test/webgen/source/test_file_system.rb +9 -4
- data/test/webgen/source/test_stacked.rb +1 -1
- data/test/webgen/source/test_tar_archive.rb +2 -2
- data/test/webgen/tag/test_breadcrumb_trail.rb +1 -1
- data/test/webgen/tag/test_coderay.rb +3 -2
- data/test/webgen/tag/test_date.rb +1 -1
- data/test/webgen/tag/test_execute_command.rb +1 -1
- data/test/webgen/tag/test_include_file.rb +1 -1
- data/test/webgen/tag/test_langbar.rb +1 -1
- data/test/webgen/tag/test_link.rb +1 -1
- data/test/webgen/tag/test_menu.rb +12 -30
- data/test/webgen/tag/test_meta_info.rb +1 -1
- data/test/webgen/tag/test_relocatable.rb +1 -1
- data/test/webgen/tag/test_tikz.rb +3 -2
- data/test/webgen/task/test_create_website.rb +2 -2
- data/test/webgen/test_blackboard.rb +11 -3
- data/test/webgen/test_bundle_loader.rb +26 -9
- data/test/webgen/test_cache.rb +1 -1
- data/test/webgen/test_cli.rb +2 -2
- data/test/webgen/test_configuration.rb +8 -9
- data/test/webgen/test_content_processor.rb +1 -1
- data/test/webgen/test_context.rb +1 -1
- data/test/webgen/test_core_ext.rb +1 -1
- data/test/webgen/test_destination.rb +1 -1
- data/test/webgen/test_error.rb +5 -5
- data/test/webgen/test_extension_manager.rb +1 -1
- data/test/webgen/test_item_tracker.rb +26 -5
- data/test/webgen/test_languages.rb +1 -1
- data/test/webgen/test_logger.rb +1 -1
- data/test/webgen/test_node.rb +1 -1
- data/test/webgen/test_node_finder.rb +2 -2
- data/test/webgen/test_page.rb +5 -5
- data/test/webgen/test_path.rb +8 -8
- data/test/webgen/test_rake_task.rb +1 -1
- data/test/webgen/test_source.rb +1 -1
- data/test/webgen/test_tag.rb +16 -24
- data/test/webgen/test_task.rb +1 -1
- data/test/webgen/test_tree.rb +1 -1
- data/test/webgen/test_utils.rb +1 -1
- data/test/webgen/test_website.rb +1 -1
- data/test/webgen/utils/test_tag_parser.rb +1 -1
- metadata +85 -105
- data/lib/webgen/cli/bundle_command.rb +0 -30
- data/lib/webgen/cli/generate_command.rb +0 -25
|
@@ -69,10 +69,9 @@ module Webgen
|
|
|
69
69
|
process_data_array(context, :css_inline) do |content|
|
|
70
70
|
result += "\n<style type=\"text/css\">/*<![CDATA[/*/\n#{content}\n/*]]>*/</style>"
|
|
71
71
|
end
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
end
|
|
72
|
+
end
|
|
73
|
+
((context.persistent[:cp_html_head] || {})[:meta] || {}).merge(context.content_node['meta'] || {}).each do |name, content|
|
|
74
|
+
result += "\n<meta name=\"#{ERB::Util.h(name)}\" content=\"#{ERB::Util.h(content)}\" />"
|
|
76
75
|
end
|
|
77
76
|
result
|
|
78
77
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'webgen/content_processor'
|
|
4
|
+
require 'webgen/vendor/rainpress'
|
|
5
|
+
|
|
6
|
+
module Webgen
|
|
7
|
+
class ContentProcessor
|
|
8
|
+
|
|
9
|
+
# Minifies CSS files.
|
|
10
|
+
module Rainpress
|
|
11
|
+
|
|
12
|
+
# Process the content of +context+ with Rainpress (a CSS minifier).
|
|
13
|
+
def self.call(context)
|
|
14
|
+
context.content = ::Rainpress.compress(context.content, context.website.config['content_processor.rainpress.options'])
|
|
15
|
+
context
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -30,9 +30,8 @@ module Webgen
|
|
|
30
30
|
class NodeTreeImporter < ::Sass::Importers::Base
|
|
31
31
|
|
|
32
32
|
# Creates a new importer that imports files from the node tree relative to the given node alcn.
|
|
33
|
-
def initialize(
|
|
34
|
-
@
|
|
35
|
-
@alcn = alcn
|
|
33
|
+
def initialize(context)
|
|
34
|
+
@context = context
|
|
36
35
|
end
|
|
37
36
|
|
|
38
37
|
# @see Base#find_relative
|
|
@@ -42,11 +41,11 @@ module Webgen
|
|
|
42
41
|
|
|
43
42
|
# @see Base#find
|
|
44
43
|
def find(name, options)
|
|
45
|
-
_find(@alcn, name, options)
|
|
44
|
+
_find(@context.ref_node.alcn, name, options)
|
|
46
45
|
end
|
|
47
46
|
|
|
48
47
|
def mtime(name, options) #:nodoc:
|
|
49
|
-
node = resolve_node(@alcn, name)
|
|
48
|
+
node = resolve_node(@context.ref_node.alcn, name)
|
|
50
49
|
node['modified_at'] if node
|
|
51
50
|
end
|
|
52
51
|
|
|
@@ -55,7 +54,7 @@ module Webgen
|
|
|
55
54
|
end
|
|
56
55
|
|
|
57
56
|
def to_s #:nodoc:
|
|
58
|
-
"webgen: #{@alcn}"
|
|
57
|
+
"webgen: #{@context.ref_node.alcn}"
|
|
59
58
|
end
|
|
60
59
|
|
|
61
60
|
#######
|
|
@@ -69,6 +68,7 @@ module Webgen
|
|
|
69
68
|
node, syntax = resolve_node(base, name)
|
|
70
69
|
return unless node
|
|
71
70
|
|
|
71
|
+
@context.website.ext.item_tracker.add(@context.dest_node, :node_content, node)
|
|
72
72
|
options[:syntax] = syntax
|
|
73
73
|
options[:filename] = node.alcn
|
|
74
74
|
options[:importer] = self
|
|
@@ -80,7 +80,7 @@ module Webgen
|
|
|
80
80
|
# Returns [node, syntax] if a node was found or nil otherwise
|
|
81
81
|
def resolve_node(base, path)
|
|
82
82
|
possible_filenames(path).each do |filename, syntax|
|
|
83
|
-
node = @website.tree.resolve_node(Webgen::Path.append(base, filename), nil)
|
|
83
|
+
node = @context.website.tree.resolve_node(Webgen::Path.append(base, filename), nil)
|
|
84
84
|
return [node, syntax] if node
|
|
85
85
|
end
|
|
86
86
|
nil
|
|
@@ -132,7 +132,7 @@ module Webgen
|
|
|
132
132
|
|
|
133
133
|
def self.default_options(context) # :nodoc:
|
|
134
134
|
opts = context.website.config['content_processor.sass.options']
|
|
135
|
-
load_paths = context.website.ext.sass_load_paths + [NodeTreeImporter.new(context
|
|
135
|
+
load_paths = context.website.ext.sass_load_paths + [NodeTreeImporter.new(context)]
|
|
136
136
|
opts.merge({
|
|
137
137
|
:filename => context.ref_node.alcn,
|
|
138
138
|
:syntax => :sass,
|
|
@@ -23,7 +23,7 @@ module Webgen
|
|
|
23
23
|
prepare_options(context)
|
|
24
24
|
context.content = context.render_block(:name => 'content',
|
|
25
25
|
:chain => [context.website.tree[context['content_processor.tikz.template']]])
|
|
26
|
-
context.content = File.binread(
|
|
26
|
+
context.content = File.binread(use_cache_or_compile(context))
|
|
27
27
|
context
|
|
28
28
|
end
|
|
29
29
|
|
|
@@ -38,48 +38,91 @@ module Webgen
|
|
|
38
38
|
end
|
|
39
39
|
private_class_method :prepare_options
|
|
40
40
|
|
|
41
|
+
# Checks whether a cached version exists and if it is usable. If not, the LaTeX document is
|
|
42
|
+
# compiled.
|
|
43
|
+
def self.use_cache_or_compile(context)
|
|
44
|
+
cwd = context.website.tmpdir('content_processor.tikz')
|
|
45
|
+
FileUtils.mkdir_p(cwd)
|
|
46
|
+
|
|
47
|
+
tex_file = File.join(cwd, context.dest_node.dest_path.tr('/', '_').sub(/\..*?$/, '.tex'))
|
|
48
|
+
basename = File.basename(tex_file, '.tex')
|
|
49
|
+
ext = File.extname(context.dest_node.dest_path)
|
|
50
|
+
image_file = tex_file.sub(/\.tex$/, ext)
|
|
51
|
+
|
|
52
|
+
if !cache_usable?(context, tex_file, image_file)
|
|
53
|
+
compile(context, cwd, tex_file, basename, ext)
|
|
54
|
+
save_cache(context, tex_file)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
image_file
|
|
58
|
+
end
|
|
59
|
+
private_class_method :use_cache_or_compile
|
|
60
|
+
|
|
41
61
|
# Compile the LaTeX document stored in the Context and convert the resulting PDF to the
|
|
42
62
|
# correct output image format specified by context[:ext] (the extension needs to include the
|
|
43
63
|
# dot).
|
|
44
64
|
#
|
|
45
65
|
# Returns the path to the created image.
|
|
46
|
-
def self.compile(context)
|
|
47
|
-
cwd = context.website.tmpdir('content_processor.tikz')
|
|
48
|
-
tex_file = File.join(cwd, context.dest_node.dest_path.tr('/', '_').sub(/\..*?$/, '.tex'))
|
|
49
|
-
FileUtils.mkdir_p(cwd)
|
|
50
|
-
File.write(tex_file, context.content)
|
|
51
|
-
|
|
52
|
-
file = File.basename(tex_file, '.tex')
|
|
53
|
-
ext = File.extname(context.dest_node.dest_path)
|
|
66
|
+
def self.compile(context, cwd, tex_file, basename, ext)
|
|
54
67
|
render_res, output_res = context['content_processor.tikz.resolution'].split(' ')
|
|
55
68
|
|
|
56
|
-
|
|
69
|
+
File.write(tex_file, context.content)
|
|
70
|
+
execute("pdflatex -shell-escape -interaction=nonstopmode -halt-on-error #{basename}.tex", cwd, context) do |status, stdout, stderr|
|
|
57
71
|
errors = (stdout+stderr).scan(/^!(.*\n.*)/).join("\n")
|
|
58
72
|
raise Webgen::RenderError.new("Error while parsing TikZ picture commands with PDFLaTeX: #{errors}",
|
|
59
73
|
'content_processor.tikz', context.dest_node, context.ref_node)
|
|
60
74
|
end
|
|
61
75
|
|
|
62
|
-
execute("pdfcrop #{
|
|
76
|
+
execute("pdfcrop #{basename}.pdf #{basename}.pdf", cwd, context)
|
|
63
77
|
|
|
64
78
|
if context['content_processor.tikz.transparent'] && ext =~ /\.png/i
|
|
65
79
|
cmd = "gs -dSAFER -dBATCH -dNOPAUSE -r#{render_res} -sDEVICE=pngalpha -dGraphicsAlphaBits=4 " +
|
|
66
|
-
"-dTextAlphaBits=4 -sOutputFile=#{
|
|
80
|
+
"-dTextAlphaBits=4 -sOutputFile=#{basename}#{ext} #{basename}.pdf"
|
|
67
81
|
else
|
|
68
|
-
cmd = "convert -density #{render_res} #{
|
|
82
|
+
cmd = "convert -density #{render_res} #{basename}.pdf #{basename}#{ext}"
|
|
69
83
|
end
|
|
70
84
|
execute(cmd, cwd, context)
|
|
71
85
|
|
|
72
86
|
if render_res != output_res
|
|
73
|
-
status, stdout, stderr = execute("identify #{
|
|
87
|
+
status, stdout, stderr = execute("identify #{basename}#{ext}", cwd, context)
|
|
74
88
|
width, height = stdout.scan(/\s\d+x\d+\s/).first.strip.split('x').collect do |s|
|
|
75
89
|
s.to_f * output_res.to_f / render_res.to_f
|
|
76
90
|
end
|
|
77
|
-
execute("convert -resize #{width}x#{height} #{
|
|
91
|
+
execute("convert -resize #{width}x#{height} #{basename}#{ext} #{basename}#{ext}", cwd, context)
|
|
78
92
|
end
|
|
79
|
-
File.join(cwd, file + ext)
|
|
80
93
|
end
|
|
81
94
|
private_class_method :compile
|
|
82
95
|
|
|
96
|
+
# Save cache data so that it is possible to use it the next time.
|
|
97
|
+
def self.save_cache(context, tex_file)
|
|
98
|
+
File.write(cache_file(tex_file), cache_data(context))
|
|
99
|
+
end
|
|
100
|
+
private_class_method :save_cache
|
|
101
|
+
|
|
102
|
+
# Check if the content of the LaTeX document or the used options have changed.
|
|
103
|
+
def self.cache_usable?(context, tex_file, image_file)
|
|
104
|
+
cfile = cache_file(tex_file)
|
|
105
|
+
File.exist?(image_file) && File.exist?(cfile) && File.binread(cfile) == cache_data(context)
|
|
106
|
+
end
|
|
107
|
+
private_class_method :cache_usable?
|
|
108
|
+
|
|
109
|
+
# The data that should be written to the cache file.
|
|
110
|
+
def self.cache_data(context)
|
|
111
|
+
("" << context.content <<
|
|
112
|
+
"\n" << context['content_processor.tikz.resolution'].to_s <<
|
|
113
|
+
"\n" << context['content_processor.tikz.transparent'].to_s <<
|
|
114
|
+
"\n" << context['content_processor.tikz.libraries'].to_s <<
|
|
115
|
+
"\n" << context['content_processor.tikz.opts'].to_s <<
|
|
116
|
+
"\n" << context['content_processor.tikz.template'].to_s).force_encoding('BINARY')
|
|
117
|
+
end
|
|
118
|
+
private_class_method :cache_data
|
|
119
|
+
|
|
120
|
+
# Return the name of the cache file for the give LaTeX file.
|
|
121
|
+
def self.cache_file(tex_file)
|
|
122
|
+
tex_file.sub(/\.tex$/, ".cache")
|
|
123
|
+
end
|
|
124
|
+
private_class_method :cache_file
|
|
125
|
+
|
|
83
126
|
# Execute the command +cmd+ in the working directory +cwd+.
|
|
84
127
|
#
|
|
85
128
|
# If the exit status is not zero, yields to the given block if one is given, or raises an error
|
data/lib/webgen/item_tracker.rb
CHANGED
|
@@ -30,7 +30,9 @@ module Webgen
|
|
|
30
30
|
# tracker extension
|
|
31
31
|
#
|
|
32
32
|
# [item_data(*item)]
|
|
33
|
-
# Return the data for the item so that it can be correctly checked later if it has changed.
|
|
33
|
+
# Return the data for the item so that it can be correctly checked later if it has changed. If
|
|
34
|
+
# data for the given item cannot be computer anymore because the item got invalid, raise an
|
|
35
|
+
# exception.
|
|
34
36
|
#
|
|
35
37
|
# [item_changed?(item_id, old_data)]
|
|
36
38
|
# Return +true+ if the item identified by its unique ID has changed. The parameter +old_data+
|
|
@@ -106,42 +108,60 @@ module Webgen
|
|
|
106
108
|
|
|
107
109
|
@item_changed = {}
|
|
108
110
|
|
|
109
|
-
@website.blackboard.add_listener(:website_initialized,
|
|
111
|
+
@website.blackboard.add_listener(:website_initialized, 'item_tracker') do
|
|
110
112
|
@cached = @website.cache[:item_tracker_data] || @cached
|
|
111
113
|
end
|
|
112
114
|
|
|
113
|
-
@website.blackboard.add_listener(:after_tree_populated,
|
|
115
|
+
@website.blackboard.add_listener(:after_tree_populated, 'item_tracker') do |node|
|
|
114
116
|
@item_data.keys.each do |uid|
|
|
115
117
|
@item_data[uid] = item_tracker(uid.first).item_data(*uid.last)
|
|
116
118
|
end
|
|
117
119
|
end
|
|
118
120
|
|
|
119
|
-
@website.blackboard.add_listener(:before_all_nodes_written,
|
|
120
|
-
# make all used item data from the previous pass current again if applicable
|
|
121
|
-
|
|
121
|
+
@website.blackboard.add_listener(:before_all_nodes_written, 'item_tracker') do
|
|
122
|
+
# make all used item data from the previous pass current again if applicable and remove
|
|
123
|
+
# invalid UIDs
|
|
124
|
+
uids_to_update = @written_nodes.each_with_object(Set.new) do |node, set|
|
|
122
125
|
next unless @website.tree[node.alcn]
|
|
123
|
-
@node_dependencies[node.alcn]
|
|
126
|
+
set.merge(@node_dependencies[node.alcn])
|
|
127
|
+
end
|
|
128
|
+
uids_to_update.each do |uid|
|
|
129
|
+
begin
|
|
124
130
|
@item_data[uid] = item_tracker(uid.first).item_data(*uid.last)
|
|
131
|
+
rescue Exception
|
|
132
|
+
@item_data.delete(uid)
|
|
133
|
+
@cached[:item_data].delete(uid)
|
|
134
|
+
@written_nodes.each do |node|
|
|
135
|
+
if @node_dependencies[node.alcn].include?(uid)
|
|
136
|
+
@node_dependencies[node.alcn].delete(uid)
|
|
137
|
+
@cached[:node_dependencies][node.alcn].delete(uid)
|
|
138
|
+
node.node_info[:item_tracker_changed_once] = true
|
|
139
|
+
end
|
|
140
|
+
end
|
|
125
141
|
end
|
|
126
142
|
end
|
|
143
|
+
|
|
127
144
|
@written_nodes = []
|
|
128
145
|
@item_changed = {}
|
|
129
146
|
end
|
|
130
147
|
|
|
131
|
-
@website.blackboard.add_listener(:after_node_written,
|
|
148
|
+
@website.blackboard.add_listener(:after_node_written, 'item_tracker') do |node|
|
|
132
149
|
@written_nodes << node
|
|
133
150
|
end
|
|
134
151
|
|
|
135
|
-
@website.blackboard.add_listener(:after_all_nodes_written,
|
|
152
|
+
@website.blackboard.add_listener(:after_all_nodes_written, 'item_tracker') do
|
|
136
153
|
# update cached data with data from the run
|
|
154
|
+
uids_to_update = Set.new
|
|
137
155
|
@written_nodes.each do |node|
|
|
138
156
|
next unless @website.tree[node.alcn]
|
|
157
|
+
node.node_info.delete(:item_tracker_changed_once)
|
|
139
158
|
@cached[:node_dependencies][node.alcn] = @node_dependencies[node.alcn]
|
|
140
|
-
@node_dependencies[node.alcn]
|
|
159
|
+
uids_to_update.merge(@node_dependencies[node.alcn])
|
|
141
160
|
end
|
|
161
|
+
uids_to_update.each {|uid| @cached[:item_data][uid] = @item_data[uid]}
|
|
142
162
|
end
|
|
143
163
|
|
|
144
|
-
@website.blackboard.add_listener(:website_generated,
|
|
164
|
+
@website.blackboard.add_listener(:website_generated, 'item_tracker') do
|
|
145
165
|
@cached[:node_dependencies].reject! {|alcn, data| !@website.tree[alcn]}
|
|
146
166
|
|
|
147
167
|
used_uids = @cached[:node_dependencies].each_with_object(Set.new) {|(_, uids), obj| obj.merge(uids)}
|
|
@@ -189,7 +209,8 @@ module Webgen
|
|
|
189
209
|
def node_changed?(node)
|
|
190
210
|
return false if @checked_nodes.include?(node)
|
|
191
211
|
@checked_nodes << node
|
|
192
|
-
|
|
212
|
+
node.node_info[:item_tracker_changed_once] ||
|
|
213
|
+
!@cached[:node_dependencies].has_key?(node.alcn) ||
|
|
193
214
|
@cached[:node_dependencies][node.alcn].any? {|uid| item_changed_by_uid?(uid)}
|
|
194
215
|
ensure
|
|
195
216
|
@checked_nodes.delete(node)
|
|
@@ -23,13 +23,13 @@ module Webgen
|
|
|
23
23
|
@stop_reporting = false
|
|
24
24
|
@nodes_to_ignore = Set.new
|
|
25
25
|
|
|
26
|
-
@website.blackboard.add_listener(:reused_existing_node,
|
|
26
|
+
@website.blackboard.add_listener(:reused_existing_node, 'item_tracker.missing_node') do |node, path|
|
|
27
27
|
@nodes_to_ignore << node
|
|
28
28
|
end
|
|
29
|
-
@website.blackboard.add_listener(:after_node_created,
|
|
29
|
+
@website.blackboard.add_listener(:after_node_created, 'item_tracker.missing_node') do |node|
|
|
30
30
|
@at_least_one_node_created = true unless @nodes_to_ignore.include?(node)
|
|
31
31
|
end
|
|
32
|
-
@website.blackboard.add_listener(:after_all_nodes_written,
|
|
32
|
+
@website.blackboard.add_listener(:after_all_nodes_written, 'item_tracker.missing_node') do
|
|
33
33
|
if @at_least_one_node_created
|
|
34
34
|
@at_least_one_node_created = false
|
|
35
35
|
else
|
|
@@ -37,7 +37,7 @@ module Webgen
|
|
|
37
37
|
end
|
|
38
38
|
@nodes_to_ignore = Set.new
|
|
39
39
|
end
|
|
40
|
-
@website.blackboard.add_listener(:website_generated,
|
|
40
|
+
@website.blackboard.add_listener(:website_generated, 'item_tracker.missing_node') do
|
|
41
41
|
@at_least_one_node_created = true
|
|
42
42
|
@stop_reporting = false
|
|
43
43
|
@nodes_to_ignore = Set.new
|
|
@@ -63,7 +63,7 @@ module Webgen
|
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
def item_description(iid, data) #:nodoc:
|
|
66
|
-
path, lang =
|
|
66
|
+
path, lang = iid
|
|
67
67
|
"Missing acn, alcn or dest path <#{path}>" << (lang.nil? ? '' : " in language '#{lang}'")
|
|
68
68
|
end
|
|
69
69
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'webgen/item_tracker'
|
|
4
|
+
|
|
5
|
+
module Webgen
|
|
6
|
+
class ItemTracker
|
|
7
|
+
|
|
8
|
+
# This class is used to track the template chain for a node.
|
|
9
|
+
#
|
|
10
|
+
# Note that only nodes that support the #template_chain method can be used (so all page,
|
|
11
|
+
# template and custom webgen nodes are okay).
|
|
12
|
+
#
|
|
13
|
+
# The item for this tracker is the node whose template chain should be tracked, i.e. add an item
|
|
14
|
+
# like this:
|
|
15
|
+
#
|
|
16
|
+
# website.ext.item_tracker.add(some_node, :template_chain, other_node)
|
|
17
|
+
#
|
|
18
|
+
class TemplateChain
|
|
19
|
+
|
|
20
|
+
def initialize(website) #:nodoc:
|
|
21
|
+
@website = website
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def item_id(node) #:nodoc:
|
|
25
|
+
node.alcn
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def item_data(alcn) #:nodoc:
|
|
29
|
+
nodes_to_alcn(@website.tree[alcn].template_chain)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def item_changed?(alcn, old_chain) #:nodoc:
|
|
33
|
+
@website.tree[alcn].nil? || item_data(alcn) != old_chain
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def referenced_nodes(alcn, data) #:nodoc:
|
|
37
|
+
[alcn]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def item_description(alcn, data) #:nodoc:
|
|
41
|
+
"Template chain for node '#{alcn}'"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def nodes_to_alcn(nodes) #:nodoc:
|
|
45
|
+
nodes.map {|node| node.alcn}
|
|
46
|
+
end
|
|
47
|
+
private :nodes_to_alcn
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'yaml'
|
|
4
|
+
require 'webgen/error'
|
|
5
|
+
|
|
6
|
+
module Webgen
|
|
7
|
+
|
|
8
|
+
module Misc
|
|
9
|
+
|
|
10
|
+
# This extension creates dummy directory index paths for directories where the proxy_path meta
|
|
11
|
+
# information does not point to a node whose lcn matches a directory index path name.
|
|
12
|
+
class DummyIndex
|
|
13
|
+
|
|
14
|
+
def initialize(website) #:nodoc:
|
|
15
|
+
@website = website
|
|
16
|
+
|
|
17
|
+
@website.blackboard.add_listener(:website_initialized, 'misc.dummy_index') do
|
|
18
|
+
if @website.config['misc.dummy_index.enabled'] && @website.config['misc.dummy_index.directory_indexes'].length > 0
|
|
19
|
+
@website.blackboard.add_listener(:website_generated, 'misc.dummy_index', &method(:create_dummy_indexes))
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Create the dummy index paths at the destination.
|
|
25
|
+
def create_dummy_indexes
|
|
26
|
+
indexes = @website.config['misc.dummy_index.directory_indexes']
|
|
27
|
+
@website.tree.node_access[:alcn].each do |_, node|
|
|
28
|
+
next if !node.is_directory? || !directory_exists?(node) || directory_index_exists?(node, indexes)
|
|
29
|
+
|
|
30
|
+
route = node.route_to(node)
|
|
31
|
+
route = node['proxy_path'].to_s if route == File.basename(node.dest_path)
|
|
32
|
+
index_path = node.dest_path + indexes.first
|
|
33
|
+
|
|
34
|
+
next if route == '' || indexes.any? {|index| index == route} ||
|
|
35
|
+
(cache[node.alcn] == [indexes.first, route] && @website.ext.destination.exists?(index_path))
|
|
36
|
+
|
|
37
|
+
@website.logger.info do
|
|
38
|
+
"[#{@website.ext.destination.exists?(index_path) ? 'update' : 'create'}] <#{index_path}> (dummy directory path pointing to #{route})"
|
|
39
|
+
end
|
|
40
|
+
cache[node.alcn] = [indexes.first, route]
|
|
41
|
+
@website.ext.destination.write(index_path, dummy_index_content(route))
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
protected :create_dummy_indexes
|
|
45
|
+
|
|
46
|
+
# Does the node directory exist at the destination?
|
|
47
|
+
def directory_exists?(node)
|
|
48
|
+
@website.ext.destination.exists?(node.dest_path)
|
|
49
|
+
end
|
|
50
|
+
protected :directory_exists?
|
|
51
|
+
|
|
52
|
+
# Is there any node with a destination path matching any of the directory index paths?
|
|
53
|
+
def directory_index_exists?(node, indexes) #:nodoc:
|
|
54
|
+
indexes.any? {|index| @website.tree.node(node.dest_path + index, :dest_path)}
|
|
55
|
+
end
|
|
56
|
+
protected :directory_index_exists?
|
|
57
|
+
|
|
58
|
+
# Return the dummy index path content for redirecting to +url+.
|
|
59
|
+
def dummy_index_content(url)
|
|
60
|
+
<<EOF
|
|
61
|
+
<!DOCTYPE html><html><head><title>Redirect</title><meta charset="UTF-8" />
|
|
62
|
+
<meta http-equiv="Refresh" content="0; url=#{url}" />
|
|
63
|
+
</head><body></body></html>
|
|
64
|
+
EOF
|
|
65
|
+
end
|
|
66
|
+
protected :dummy_index_content
|
|
67
|
+
|
|
68
|
+
# Return the cache used by this extension.
|
|
69
|
+
def cache
|
|
70
|
+
@website.cache['misc.dummy_index.data'] ||= {}
|
|
71
|
+
end
|
|
72
|
+
protected :cache
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|