webgen 0.5.5 → 0.5.6

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.
Files changed (101) hide show
  1. data/ChangeLog +3662 -0
  2. data/Rakefile +8 -1
  3. data/VERSION +1 -1
  4. data/data/webgen/website_styles/1024px/src/default.template +1 -1
  5. data/data/webgen/website_styles/andreas00/src/default.template +1 -1
  6. data/data/webgen/website_styles/andreas01/src/default.template +2 -1
  7. data/data/webgen/website_styles/andreas03/src/default.template +1 -1
  8. data/data/webgen/website_styles/andreas04/src/default.template +1 -1
  9. data/data/webgen/website_styles/andreas05/src/default.template +1 -1
  10. data/data/webgen/website_styles/andreas06/src/default.template +1 -1
  11. data/data/webgen/website_styles/andreas07/src/default.template +1 -1
  12. data/data/webgen/website_styles/andreas08/src/default.template +1 -1
  13. data/data/webgen/website_styles/andreas09/src/default.template +1 -1
  14. data/data/webgen/website_styles/simple/src/default.template +1 -1
  15. data/doc/contentprocessor/fragments.page +25 -0
  16. data/doc/extensions.page +1 -1
  17. data/doc/manual.page +33 -15
  18. data/doc/reference_configuration.page +339 -62
  19. data/doc/reference_metainfo.page +11 -2
  20. data/doc/sourcehandler/feed.page +19 -4
  21. data/doc/sourcehandler/page.page +0 -16
  22. data/doc/tag/langbar.page +8 -1
  23. data/doc/tag/link.page +44 -0
  24. data/doc/tag/tikz.page +158 -0
  25. data/lib/webgen/cli.rb +4 -4
  26. data/lib/webgen/common/sitemap.rb +2 -3
  27. data/lib/webgen/configuration.rb +3 -1
  28. data/lib/webgen/contentprocessor.rb +1 -0
  29. data/lib/webgen/contentprocessor/blocks.rb +0 -2
  30. data/lib/webgen/contentprocessor/context.rb +0 -3
  31. data/lib/webgen/contentprocessor/erubis.rb +0 -2
  32. data/lib/webgen/contentprocessor/fragments.rb +23 -0
  33. data/lib/webgen/default_config.rb +15 -2
  34. data/lib/webgen/languages.rb +9 -0
  35. data/lib/webgen/logger.rb +18 -1
  36. data/lib/webgen/node.rb +50 -25
  37. data/lib/webgen/page.rb +26 -16
  38. data/lib/webgen/path.rb +20 -10
  39. data/lib/webgen/sourcehandler.rb +85 -69
  40. data/lib/webgen/sourcehandler/base.rb +38 -15
  41. data/lib/webgen/sourcehandler/copy.rb +2 -2
  42. data/lib/webgen/sourcehandler/directory.rb +16 -13
  43. data/lib/webgen/sourcehandler/feed.rb +6 -12
  44. data/lib/webgen/sourcehandler/fragment.rb +6 -11
  45. data/lib/webgen/sourcehandler/memory.rb +41 -0
  46. data/lib/webgen/sourcehandler/metainfo.rb +21 -21
  47. data/lib/webgen/sourcehandler/page.rb +7 -27
  48. data/lib/webgen/sourcehandler/sitemap.rb +0 -2
  49. data/lib/webgen/sourcehandler/template.rb +0 -4
  50. data/lib/webgen/sourcehandler/virtual.rb +18 -18
  51. data/lib/webgen/tag.rb +2 -0
  52. data/lib/webgen/tag/breadcrumbtrail.rb +1 -4
  53. data/lib/webgen/tag/coderay.rb +0 -3
  54. data/lib/webgen/tag/date.rb +0 -2
  55. data/lib/webgen/tag/executecommand.rb +1 -2
  56. data/lib/webgen/tag/includefile.rb +1 -3
  57. data/lib/webgen/tag/langbar.rb +2 -5
  58. data/lib/webgen/tag/link.rb +23 -0
  59. data/lib/webgen/tag/menu.rb +1 -4
  60. data/lib/webgen/tag/metainfo.rb +0 -2
  61. data/lib/webgen/tag/relocatable.rb +2 -3
  62. data/lib/webgen/tag/sitemap.rb +0 -3
  63. data/lib/webgen/tag/tikz.rb +117 -0
  64. data/lib/webgen/tree.rb +11 -6
  65. data/lib/webgen/version.rb +1 -1
  66. data/lib/webgen/website.rb +2 -1
  67. data/test/test_cli.rb +14 -0
  68. data/test/test_common_sitemap.rb +4 -4
  69. data/test/test_contentprocessor_context.rb +1 -1
  70. data/test/test_contentprocessor_fragments.rb +40 -0
  71. data/test/test_contentprocessor_redcloth.rb +1 -0
  72. data/test/test_contentprocessor_tags.rb +1 -1
  73. data/test/test_languages.rb +12 -0
  74. data/test/test_logger.rb +19 -0
  75. data/test/test_node.rb +35 -15
  76. data/test/test_output_filesystem.rb +1 -1
  77. data/test/test_page.rb +15 -6
  78. data/test/test_path.rb +37 -5
  79. data/test/test_source_filesystem.rb +1 -1
  80. data/test/test_source_stacked.rb +1 -1
  81. data/test/test_sourcehandler_base.rb +30 -1
  82. data/test/test_sourcehandler_copy.rb +1 -1
  83. data/test/test_sourcehandler_directory.rb +16 -1
  84. data/test/test_sourcehandler_feed.rb +9 -8
  85. data/test/test_sourcehandler_fragment.rb +1 -1
  86. data/test/test_sourcehandler_memory.rb +42 -0
  87. data/test/test_sourcehandler_metainfo.rb +23 -21
  88. data/test/test_sourcehandler_page.rb +5 -12
  89. data/test/test_sourcehandler_template.rb +1 -1
  90. data/test/test_sourcehandler_virtual.rb +2 -2
  91. data/test/test_tag_base.rb +0 -1
  92. data/test/test_tag_breadcrumbtrail.rb +4 -4
  93. data/test/test_tag_includefile.rb +3 -3
  94. data/test/test_tag_langbar.rb +12 -7
  95. data/test/test_tag_link.rb +61 -0
  96. data/test/test_tag_menu.rb +7 -7
  97. data/test/test_tag_metainfo.rb +1 -1
  98. data/test/test_tag_relocatable.rb +1 -1
  99. data/test/test_tag_tikz.rb +66 -0
  100. data/test/test_tree.rb +8 -9
  101. metadata +15 -2
@@ -50,6 +50,15 @@ module Webgen
50
50
  self.to_s <=> other.to_s
51
51
  end
52
52
 
53
+ def eql?(other) #:nodoc:
54
+ (other.is_a?(self.class) && other.to_s == self.to_s) ||
55
+ (other.is_a?(String) && self.to_s == other)
56
+ end
57
+
58
+ def hash #:nodoc:
59
+ self.to_s.hash
60
+ end
61
+
53
62
  end
54
63
 
55
64
 
@@ -27,11 +27,28 @@ module Webgen
27
27
  end
28
28
  self.level = ::Logger::WARN
29
29
  self.verbosity = :normal
30
+ @marks = []
30
31
  end
31
32
 
32
33
  # Returns the output of the logger when #sync is +false+. Otherwise an empty string is returned.
33
34
  def log_output
34
- @sync ? '' : @logio.string
35
+ if @sync
36
+ ''
37
+ else
38
+ out = @logio.string.dup
39
+ @marks.reverse.each_with_index do |mark, index|
40
+ out.insert(mark, " INFO -- Log messages for run #{@marks.length - index} are following\n")
41
+ end if out.length > 0
42
+ out
43
+ end
44
+ end
45
+
46
+ # Only used when #sync is +false: Mark the location in the log stream where a new update/write
47
+ # run begins.
48
+ def mark_new_cycle
49
+ if !@sync
50
+ @marks << @logio.string.length
51
+ end
35
52
  end
36
53
 
37
54
  # The severity threshold level.
@@ -46,17 +46,6 @@ module Webgen
46
46
  # Meta information associated with the node.
47
47
  attr_reader :meta_info
48
48
 
49
- # Set by other objects to +true+ if they think the object has changed since the last run. Must
50
- # not be set to +false+ once it is +true+!
51
- attr_accessor :dirty
52
-
53
- # Set by other objects to +true+ if the meta information of the node has changed since the last
54
- # run. Must not be set to +false+ once it is +true+!
55
- attr_accessor :dirty_meta_info
56
-
57
- # Has the node been created or has it been read from the cache?
58
- attr_accessor :created
59
-
60
49
  # Create a new Node instance.
61
50
  #
62
51
  # +parent+ (immutable)::
@@ -78,17 +67,29 @@ module Webgen
78
67
  # found, the node is language neutral.
79
68
  def initialize(parent, path, cn, meta_info = {})
80
69
  @parent = parent
81
- @path = path.freeze
82
70
  @cn = cn.chomp('/').freeze
83
- @lang = meta_info.delete('lang').freeze
84
- @lang = nil unless is_file?
85
- @meta_info = meta_info
86
71
  @children = []
87
- @dirty = true
88
- @created = true
72
+ reinit(path, meta_info)
89
73
  init_rest
90
74
  end
91
75
 
76
+ # Re-initializes an already initialized node and resets it to its pristine state.
77
+ def reinit(path, meta_info = {})
78
+ old_path = @path
79
+ @path = path.freeze
80
+ @lang = Webgen::LanguageManager.language_for_code(meta_info.delete('lang'))
81
+ @lang = nil unless is_file?
82
+ @meta_info = meta_info
83
+ @flags = Set.new([:dirty, :created])
84
+ if @tree
85
+ @tree.node_access[:path].delete(old_path) if old_path
86
+ @tree.register_path(self)
87
+ self.node_info.clear
88
+ self.node_info[:used_nodes] = Set.new
89
+ self.node_info[:used_meta_info_nodes] = Set.new
90
+ end
91
+ end
92
+
92
93
  # Return the meta information item for +key+.
93
94
  def [](key)
94
95
  @meta_info[key]
@@ -116,26 +117,50 @@ module Webgen
116
117
  # Check if the node is the root node.
117
118
  def is_root?; self == tree.root; end
118
119
 
120
+ # Check if the node is flagged with one of the following:
121
+ #
122
+ # :created:: Has the node been created or has it been read from the cache?
123
+ # :reinit:: Does the node need to be reinitialized?
124
+ # :dirty:: Set by other objects to +true+ if they think the object has changed since the last
125
+ # run. Must not be set to +false+ once it is +true+!
126
+ # :dirty_meta_info:: Set by other objects to +true+ if the meta information of the node has
127
+ # changed since the last run. Must not be set to +false+ once it is +true+!
128
+ def flagged(key)
129
+ @flags.include?(key)
130
+ end
131
+
132
+ # Flag the node with the +keys+. See #flagged for valid keys.
133
+ def flag(*keys)
134
+ @flags += keys
135
+ website.blackboard.dispatch_msg(:node_flagged, self, keys)
136
+ end
137
+
138
+ # Remove the flags +keys+ from the node.
139
+ def unflag(*keys)
140
+ @flags.subtract(keys)
141
+ website.blackboard.dispatch_msg(:node_unflagged, self, keys)
142
+ end
143
+
119
144
  # Return +true+ if the node has changed since the last webgen run. If it has changed, +dirty+ is
120
145
  # set to +true+.
121
146
  def changed?
122
147
  if_not_checked(:node) do
123
- @dirty = @dirty || meta_info_changed?
124
- @dirty = node_info[:used_nodes].any? {|n| n != @absolute_lcn && (!tree[n] || tree[n].changed?)} unless @dirty
125
- website.blackboard.dispatch_msg(:node_changed?, self) unless @dirty
148
+ flag(:dirty) if meta_info_changed? ||
149
+ node_info[:used_nodes].any? {|n| n != @absolute_lcn && (!tree[n] || tree[n].changed?)}
150
+ website.blackboard.dispatch_msg(:node_changed?, self) unless flagged(:dirty)
126
151
  end
127
- @dirty
152
+ flagged(:dirty)
128
153
  end
129
154
 
130
155
  # Return +true+ if the meta information of the node has changed.
131
156
  def meta_info_changed?
132
157
  if_not_checked(:meta_info) do
133
- @dirty_meta_info = node_info[:used_meta_info_nodes].any? do |n|
158
+ flag(:dirty_meta_info) if node_info[:used_meta_info_nodes].any? do |n|
134
159
  n != @absolute_lcn && (!tree[n] || tree[n].meta_info_changed?)
135
- end unless @dirty_meta_info
136
- website.blackboard.dispatch_msg(:node_meta_info_changed?, self) unless @dirty_meta_info
160
+ end
161
+ website.blackboard.dispatch_msg(:node_meta_info_changed?, self) unless flagged(:dirty_meta_info)
137
162
  end
138
- @dirty_meta_info
163
+ flagged(:dirty_meta_info)
139
164
  end
140
165
 
141
166
  # Return an informative representation of the node.
@@ -55,14 +55,17 @@ module Webgen
55
55
  # the information. The +meta_info+ parameter can be used to provide default meta information.
56
56
  def from_data(data, meta_info = {})
57
57
  md = /(#{RE_META_INFO})?(.*)/m.match(normalize_eol(data))
58
- if md[1].nil? && data =~ RE_META_INFO_START
59
- raise WebgenPageFormatError, 'Found start line for meta information block but no valid meta information block'
60
- end
61
- meta_info = meta_info.merge(md[1].nil? ? {} : parse_meta_info(md[1]))
58
+ meta_info = meta_info.merge(parse_meta_info(md[1], data))
62
59
  blocks = parse_blocks(md[2] || '', meta_info)
63
60
  new(meta_info, blocks)
64
61
  end
65
62
 
63
+ # Parse the given string +data+ in Webgen Page Format and return the found meta information.
64
+ def meta_info_from_data(data)
65
+ md = /(#{RE_META_INFO})?/m.match(normalize_eol(data))
66
+ parse_meta_info(md[1], data)
67
+ end
68
+
66
69
  #######
67
70
  private
68
71
  #######
@@ -72,17 +75,24 @@ module Webgen
72
75
  data.gsub(/\r\n?/, "\n")
73
76
  end
74
77
 
75
- # Parse the meta info string +data+ and return the hash with the meta information.
76
- def parse_meta_info(data)
77
- begin
78
- meta_info = YAML::load(data)
79
- unless meta_info.kind_of?(Hash)
80
- raise WebgenPageFormatError, "Invalid structure of meta information block: expected YAML hash but found #{meta_info.class}"
78
+ # Parse the meta info string in +mi_data+ and return the hash with the meta information. The
79
+ # original +data+ is used for checking the validness of the meta information block.
80
+ def parse_meta_info(mi_data, data)
81
+ if mi_data.nil? && data =~ RE_META_INFO_START
82
+ raise WebgenPageFormatError, 'Found start line for meta information block but no valid meta information block'
83
+ elsif mi_data.nil?
84
+ {}
85
+ else
86
+ begin
87
+ meta_info = YAML::load(mi_data.to_s)
88
+ unless meta_info.kind_of?(Hash)
89
+ raise WebgenPageFormatError, "Invalid structure of meta information block: expected YAML hash but found #{meta_info.class}"
90
+ end
91
+ rescue ArgumentError => e
92
+ raise WebgenPageFormatError, e.message
81
93
  end
82
- rescue ArgumentError => e
83
- raise WebgenPageFormatError, e.message
94
+ meta_info
84
95
  end
85
- meta_info
86
96
  end
87
97
 
88
98
  # Parse all blocks in +data+ and return them. Meta information can be provided in +meta_info+
@@ -96,7 +106,7 @@ module Webgen
96
106
  options, content = *block_data
97
107
  md = RE_BLOCKS_OPTIONS.match(options.to_s)
98
108
  raise(WebgenPageFormatError, "Found invalid blocks starting line for block #{index+1}: #{options}") if content =~ /\A---/ || md.nil?
99
- options = Hash[*md[1].to_s.scan(/(\w+):([^\s]*)/).map {|k,v| [k, YAML::load(v)]}.flatten]
109
+ options = Hash[*md[1].to_s.scan(/(\w+):([^\s]*)/).map {|k,v| [k, (v == '' ? nil : YAML::load(v))]}.flatten]
100
110
  options = (meta_info['blocks']['default'] || {} rescue {}).
101
111
  merge((meta_info['blocks'][index+1] || {} rescue {})).
102
112
  merge(options)
@@ -118,12 +128,12 @@ module Webgen
118
128
  # The contents of the meta information block.
119
129
  attr_reader :meta_info
120
130
 
121
- # The array of blocks for the page.
131
+ # The hash of blocks for the page.
122
132
  attr_reader :blocks
123
133
 
124
134
  # Create a new Page object with the meta information provided in +meta_info+ and the given
125
135
  # +blocks+.
126
- def initialize(meta_info = {}, blocks = nil)
136
+ def initialize(meta_info = {}, blocks = {})
127
137
  @meta_info = meta_info
128
138
  @blocks = blocks
129
139
  end
@@ -35,11 +35,24 @@ module Webgen
35
35
  end
36
36
 
37
37
 
38
+ # Return +true+ if the given +path+ matches the given +pattern+ (trailing slashes of directories
39
+ # are not respected). For information on which patterns are supported, have a look at the
40
+ # documentation of File.fnmatch.
41
+ def self.match(path, pattern)
42
+ path = path.to_s.chomp('/') unless path == '/'
43
+ pattern = pattern.to_s.chomp('/') unless pattern == '/'
44
+ File.fnmatch(pattern, path, File::FNM_DOTMATCH|File::FNM_CASEFOLD|File::FNM_PATHNAME)
45
+ end
46
+
47
+
38
48
  include Comparable
39
49
 
40
- # The full source path.
50
+ # The full path.
41
51
  attr_accessor :path
42
52
 
53
+ # The source path that lead to the creation of this path.
54
+ attr_accessor :source_path
55
+
43
56
  # The basename part of the path.
44
57
  attr_accessor :basename
45
58
 
@@ -55,11 +68,13 @@ module Webgen
55
68
  # Extracted meta information for the path.
56
69
  attr_accessor :meta_info
57
70
 
58
- # Create a new Path object for +path+. The optional block needs to return an IO object for the
59
- # content of the path.
60
- def initialize(path, &ioblock)
71
+ # Create a new Path object for +path+. The optional +source_path+ parameter specifies the path
72
+ # that lead to the creation of this path. The optional block needs to return an IO object for
73
+ # the content of the path.
74
+ def initialize(path, source_path = path, &ioblock)
61
75
  @meta_info = {}
62
76
  @io = SourceIO.new(&ioblock) if block_given?
77
+ @source_path = source_path
63
78
  analyse(path)
64
79
  end
65
80
 
@@ -70,6 +85,7 @@ module Webgen
70
85
  temp.path = temp.path.sub(/^#{Regexp.escape(prefix.chomp("/"))}/, '') if prefix #"
71
86
  reanalyse = (@path == '/' || temp.path == '/')
72
87
  temp.path = File.join(mp, temp.path)
88
+ temp.source_path = temp.path if @path == @source_path
73
89
  if reanalyse
74
90
  temp.send(:analyse, temp.path)
75
91
  else
@@ -131,12 +147,6 @@ module Webgen
131
147
  end
132
148
  alias_method(:eql?, :==)
133
149
 
134
- # Return +true+ if the localized path matches the given +pattern+. For information on which
135
- # patterns are supported, have a look at the documentation of File.fnmatch.
136
- def =~(pattern)
137
- File.fnmatch(pattern, File.join(@directory, lcn), File::FNM_DOTMATCH|File::FNM_CASEFOLD|File::FNM_PATHNAME)
138
- end
139
-
140
150
  # Implemented sothat a Path looks like a String when used as key in a hash.
141
151
  def <=>(other)
142
152
  @path <=> other.to_str
@@ -19,6 +19,7 @@ module Webgen
19
19
  autoload :Virtual, 'webgen/sourcehandler/virtual'
20
20
  autoload :Feed, 'webgen/sourcehandler/feed'
21
21
  autoload :Sitemap, 'webgen/sourcehandler/sitemap'
22
+ autoload :Memory, 'webgen/sourcehandler/memory'
22
23
 
23
24
  # This class is used by Website to do the actual rendering of the website. It
24
25
  #
@@ -39,52 +40,90 @@ module Webgen
39
40
  # Render the nodes provided in the +tree+. Before the actual rendering is done, the sources
40
41
  # are checked (nodes for deleted sources are deleted, nodes for new and changed sources).
41
42
  def render(tree)
42
- # Add new and changed nodes, remove nodes of deleted paths
43
- puts "Generating tree..."
44
- time = Benchmark.measure do
45
- used_paths = Set.new
46
- paths = Set.new([nil])
47
- while paths.length > 0
48
- used_paths += (paths = Set.new(find_all_source_paths.keys) - used_paths - clean(tree))
49
- create_nodes_from_paths(tree, paths)
43
+ begin
44
+ website.logger.mark_new_cycle if website.logger
45
+
46
+ puts "Updating tree..."
47
+ time = Benchmark.measure do
50
48
  website.cache.reset_volatile_cache
49
+ update_tree(tree)
51
50
  end
52
- end
53
- puts "...done in " + ('%2.4f' % time.real) + ' seconds'
54
-
55
- output = website.blackboard.invoke(:output_instance)
51
+ puts "...done in " + ('%2.4f' % time.real) + ' seconds'
56
52
 
57
- puts "Writing changed nodes..."
58
- time = Benchmark.measure do
59
- tree.node_access[:alcn].sort.each do |name, node|
60
- node.dirty_meta_info = node.created = false
61
- next if node == tree.dummy_root || !node.dirty
62
- node.dirty = false
63
-
64
- begin
65
- if !node['no_output'] && (content = node.content)
66
- puts " "*4 + name, :verbose
67
- type = if node.is_directory?
68
- :directory
69
- elsif node.is_fragment?
70
- :fragment
71
- else
72
- :file
73
- end
74
- output.write(node.path, content, type)
75
- end
76
- rescue
77
- raise RuntimeError, "Error while processing <#{node.absolute_lcn}>: #{$!.message}", $!.backtrace
78
- end
53
+ puts "Writing changed nodes..."
54
+ time = Benchmark.measure do
55
+ write_tree(tree)
79
56
  end
80
- end
81
- puts "...done in " + ('%2.4f' % time.real) + ' seconds'
57
+ puts "...done in " + ('%2.4f' % time.real) + ' seconds'
58
+ end while tree.node_access[:alcn].any? {|name,node| node.flagged(:created) || node.flagged(:reinit)}
82
59
  end
83
60
 
84
61
  #######
85
62
  private
86
63
  #######
87
64
 
65
+ # Update the +tree+ by creating/reinitializing all needed nodes.
66
+ def update_tree(tree)
67
+ unused_paths = Set.new
68
+ begin
69
+ used_paths = Set.new(find_all_source_paths.keys) - unused_paths
70
+ paths_to_use = Set.new
71
+ nodes_to_delete = Set.new
72
+
73
+ tree.node_access[:alcn].each do |alcn, node|
74
+ next if node == tree.dummy_root
75
+ used_paths.delete(node.node_info[:src])
76
+
77
+ deleted = !find_all_source_paths.include?(node.node_info[:src])
78
+ if deleted
79
+ nodes_to_delete << node
80
+ #TODO: delete output path
81
+ elsif (!node.flagged(:created) && find_all_source_paths[node.node_info[:src]].changed?) || node.meta_info_changed?
82
+ node.flag(:reinit)
83
+ paths_to_use << node.node_info[:src]
84
+ elsif node.changed?
85
+ # nothing to be done here
86
+ end
87
+ end
88
+
89
+ nodes_to_delete.each {|node| tree.delete_node(node)}
90
+ used_paths.merge(paths_to_use)
91
+ paths = create_nodes_from_paths(tree, used_paths.to_a.sort)
92
+ unused_paths.merge(used_paths - paths)
93
+ tree.node_access[:alcn].each {|name, node| tree.delete_node(node) if node.flagged(:reinit)}
94
+ website.cache.reset_volatile_cache
95
+ end until used_paths.empty?
96
+ end
97
+
98
+ # Write out all changed nodes of the +tree+.
99
+ def write_tree(tree)
100
+ output = website.blackboard.invoke(:output_instance)
101
+
102
+ tree.node_access[:alcn].select do |name, node|
103
+ use_node = (node != tree.dummy_root && node.flagged(:dirty))
104
+ node.unflag(:dirty_meta_info)
105
+ node.unflag(:created)
106
+ node.unflag(:dirty)
107
+ use_node
108
+ end.sort.each do |name, node|
109
+ next if node['no_output'] || !(content = node.content)
110
+
111
+ begin
112
+ puts " "*4 + name, :verbose
113
+ type = if node.is_directory?
114
+ :directory
115
+ elsif node.is_fragment?
116
+ :fragment
117
+ else
118
+ :file
119
+ end
120
+ output.write(node.path, content, type)
121
+ rescue
122
+ raise RuntimeError, "Error while processing <#{node.absolute_lcn}>: #{$!.message}", $!.backtrace
123
+ end
124
+ end
125
+ end
126
+
88
127
  # Return a hash with all source paths.
89
128
  def find_all_source_paths
90
129
  if !defined?(@paths)
@@ -94,7 +133,7 @@ module Webgen
94
133
  @paths = {}
95
134
  source.paths.each do |path|
96
135
  if !(website.config['sourcehandler.ignore'].any? {|pat| File.fnmatch(pat, path, File::FNM_CASEFOLD|File::FNM_DOTMATCH)})
97
- @paths[path.path] = path
136
+ @paths[path.source_path] = path
98
137
  end
99
138
  end
100
139
  end
@@ -115,16 +154,20 @@ module Webgen
115
154
 
116
155
  # Use the source handlers to create nodes for the +paths+ in the +tree+.
117
156
  def create_nodes_from_paths(tree, paths)
157
+ used_paths = Set.new
118
158
  website.config['sourcehandler.invoke'].sort.each do |priority, shns|
119
159
  shns.each do |shn|
120
160
  sh = website.cache.instance(shn)
121
- paths_for_handler(shn, paths).sort.each do |path|
161
+ handler_paths = paths_for_handler(shn, paths)
162
+ used_paths.merge(handler_paths)
163
+ handler_paths.sort {|a,b| a.path.length <=> b.path.length}.each do |path|
122
164
  parent_dir = path.directory.split('/').collect {|p| Path.new(p).cn}.join('/')
123
165
  parent_dir += '/' if path != '/' && parent_dir == ''
124
166
  create_nodes(tree, parent_dir, path, sh)
125
167
  end
126
168
  end
127
169
  end
170
+ used_paths
128
171
  end
129
172
 
130
173
  # Prepare everything to create nodes under the absolute lcn path +parent_path_name+ in the
@@ -142,7 +185,7 @@ module Webgen
142
185
  *nodes = if block_given?
143
186
  yield(parent, path)
144
187
  else
145
- source_handler.create_node(parent, path.dup)
188
+ source_handler.create_node(parent, path)
146
189
  end
147
190
  nodes.flatten.compact.each do |node|
148
191
  website.blackboard.dispatch_msg(:after_node_created, node)
@@ -160,39 +203,12 @@ module Webgen
160
203
  # take the node's path's +modified_at+ meta information into account since that changes on
161
204
  # every path change.
162
205
  def meta_info_changed?(node)
163
- path = node.node_info[:src]
206
+ path = node.node_info[:creation_path]
164
207
  old_mi = website.cache[:sourcehandler_path_mi][[path, node.node_info[:processor]]]
165
208
  old_mi.delete('modified_at')
166
- new_mi = default_meta_info(@paths[path], node.node_info[:processor])
209
+ new_mi = default_meta_info(@paths[path] || Webgen::Path.new(path), node.node_info[:processor])
167
210
  new_mi.delete('modified_at')
168
- node.dirty_meta_info = true if !old_mi || old_mi != new_mi
169
- end
170
-
171
- # Clean the +tree+ by deleting nodes which have changed or which don't have an associated
172
- # source anymore. Return all paths for which nodes need to be created.
173
- def clean(tree)
174
- paths_to_delete = Set.new
175
- paths_not_to_delete = Set.new
176
- nodes_to_be_deleted = Set.new
177
- tree.node_access[:alcn].each do |alcn, node|
178
- next if node == tree.dummy_root || tree[alcn].nil?
179
-
180
- deleted = !find_all_source_paths.include?(node.node_info[:src])
181
- if !node.created && (deleted ||
182
- find_all_source_paths[node.node_info[:src]].changed? ||
183
- node.changed?)
184
- paths_not_to_delete << node.node_info[:src]
185
- nodes_to_be_deleted << [node, deleted]
186
- else
187
- paths_to_delete << node.node_info[:src]
188
- end
189
- end
190
-
191
- nodes_to_be_deleted.each {|node, deleted| tree.delete_node(node, deleted)}
192
- #TODO: delete output path
193
-
194
- # source paths that should be used
195
- paths_to_delete - paths_not_to_delete
211
+ node.flag(:dirty_meta_info) if !old_mi || old_mi != new_mi
196
212
  end
197
213
 
198
214
  end