webgen 1.0.0.beta3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|