lib/webgen/sourcehandler.rb in gettalong-webgen-0.5.8.20090507 vs lib/webgen/sourcehandler.rb in gettalong-webgen-0.5.9.20090620

- old
+ new

@@ -26,91 +26,113 @@ # This class is used by Website to do the actual rendering of the website. It # # * collects all source paths using the source classes # * creates nodes using the source handler classes # * writes changed nodes out using an output class + # * deletes old nodes class Main include WebsiteAccess include Loggable def initialize #:nodoc: website.blackboard.add_service(:create_nodes, method(:create_nodes)) + website.blackboard.add_service(:create_nodes_from_paths, method(:create_nodes_from_paths)) website.blackboard.add_service(:source_paths, method(:find_all_source_paths)) website.blackboard.add_listener(:node_meta_info_changed?, method(:meta_info_changed?)) + + website.blackboard.add_listener(:before_node_deleted) do |node| + website.blackboard.invoke(:output_instance).delete(node.path) + end if website.config['output.do_deletion'] end - # Render the nodes provided in the +tree+. Before the actual rendering is done, the sources - # are checked (nodes for deleted sources are deleted, nodes for new and changed sources). - def render(tree) + # Render the current website. Before the actual rendering is done, the sources are checked for + # changes, i.e. nodes for deleted sources are deleted, nodes for new and changed sources are + # updated. + def render begin website.logger.mark_new_cycle if website.logger puts "Updating tree..." time = Benchmark.measure do website.cache.reset_volatile_cache - update_tree(tree) + update_tree end puts "...done in " + ('%2.4f' % time.real) + ' seconds' - if !tree.root + if !website.tree.root puts 'No source files found - maybe not a webgen website?' return nil end puts "Writing changed nodes..." time = Benchmark.measure do - write_tree(tree) + write_tree end puts "...done in " + ('%2.4f' % time.real) + ' seconds' - end while tree.node_access[:alcn].any? {|name,node| node.flagged?(:created) || node.flagged?(:reinit)} + end while website.tree.node_access[:alcn].any? {|name,node| node.flagged?(:created) || node.flagged?(:reinit)} :success end ####### private ####### - # Update the +tree+ by creating/reinitializing all needed nodes. - def update_tree(tree) + # Update the <tt>website.tree</tt> by creating/reinitializing all needed nodes. + def update_tree unused_paths = Set.new + referenced_nodes = Set.new + all_but_passive_paths = Set.new(find_all_source_paths.select {|name, path| !path.passive?}.collect {|name, path| name}) begin - used_paths = Set.new(find_all_source_paths.keys) - unused_paths + used_paths = all_but_passive_paths - unused_paths paths_to_use = Set.new nodes_to_delete = Set.new + passive_nodes = Set.new - tree.node_access[:alcn].each do |alcn, node| - next if node == tree.dummy_root + website.tree.node_access[:alcn].each do |alcn, node| + next if node == website.tree.dummy_root used_paths.delete(node.node_info[:src]) - deleted = !find_all_source_paths.include?(node.node_info[:src]) - if deleted + src_path = find_all_source_paths[node.node_info[:src]] + if !src_path nodes_to_delete << node - #TODO: delete output path - elsif (!node.flagged?(:created) && find_all_source_paths[node.node_info[:src]].changed?) || node.meta_info_changed? + elsif (!node.flagged?(:created) && src_path.changed?) || node.meta_info_changed? node.flag(:reinit) paths_to_use << node.node_info[:src] elsif node.changed? - # nothing to be done here + # nothing to be done here but method node.changed? has to be called end + + if src_path && src_path.passive? + passive_nodes << node + elsif src_path + referenced_nodes += node.node_info[:used_meta_info_nodes] + node.node_info[:used_nodes] + end end - nodes_to_delete.each {|node| tree.delete_node(node)} + # add unused passive nodes to node_to_delete set + unreferenced_passive_nodes, other_passive_nodes = passive_nodes.partition do |pnode| + !referenced_nodes.include?(pnode.alcn) + end + refs = other_passive_nodes.collect {|n| (n.node_info[:used_meta_info_nodes] + n.node_info[:used_nodes]).to_a}.flatten + unreferenced_passive_nodes.each {|n| nodes_to_delete << n if !refs.include?(n.alcn)} + + nodes_to_delete.each {|node| website.tree.delete_node(node)} used_paths.merge(paths_to_use) - paths = create_nodes_from_paths(tree, used_paths.to_a.sort) + paths = create_nodes_from_paths(used_paths.to_a.sort) unused_paths.merge(used_paths - paths) - tree.node_access[:alcn].each {|name, node| tree.delete_node(node) if node.flagged?(:reinit)} + website.tree.node_access[:alcn].each {|name, node| website.tree.delete_node(node) if node.flagged?(:reinit)} website.cache.reset_volatile_cache end until used_paths.empty? end - # Write out all changed nodes of the +tree+. - def write_tree(tree) + # Write out all changed nodes of the <tt>website.tree</tt>. + def write_tree output = website.blackboard.invoke(:output_instance) - tree.node_access[:alcn].select do |name, node| - use_node = (node != tree.dummy_root && node.flagged?(:dirty)) + website.tree.node_access[:alcn].select do |name, node| + use_node = (node != website.tree.dummy_root && node.flagged?(:dirty)) node.unflag(:dirty_meta_info) node.unflag(:created) node.unflag(:dirty) use_node end.sort.each do |name, node| @@ -125,21 +147,27 @@ else :file end output.write(node.path, content, type) rescue - raise RuntimeError, "Error while processing <#{node.absolute_lcn}>: #{$!.message}", $!.backtrace + raise RuntimeError, "Error while processing <#{node.alcn}>: #{$!.message}", $!.backtrace end end end # Return a hash with all source paths. def find_all_source_paths if !defined?(@paths) - source = Webgen::Source::Stacked.new(website.config['sources'].collect do |mp, name, *args| - [mp, constant(name).new(*args)] - end) + active_source = Webgen::Source::Stacked.new(website.config['sources'].collect do |mp, name, *args| + [mp, constant(name).new(*args)] + end) + passive_source = Webgen::Source::Stacked.new(website.config['passive_sources'].collect do |mp, name, *args| + [mp, constant(name).new(*args)] + end, true) + passive_source.paths.each {|path| path.passive = true } + source = Webgen::Source::Stacked.new([['/', active_source], ['/', passive_source]]) + @paths = {} source.paths.each do |path| if !(website.config['sourcehandler.ignore'].any? {|pat| File.fnmatch(pat, path, File::FNM_CASEFOLD|File::FNM_DOTMATCH)}) @paths[path.source_path] = path end @@ -153,48 +181,46 @@ patterns = website.config['sourcehandler.patterns'][name] return [] if patterns.nil? options = (website.config['sourcehandler.casefold'] ? File::FNM_CASEFOLD : 0) | (website.config['sourcehandler.use_hidden_files'] ? File::FNM_DOTMATCH : 0) - find_all_source_paths.values_at(*paths).select do |path| + find_all_source_paths.values_at(*paths).compact.select do |path| patterns.any? {|pat| File.fnmatch(pat, path, options)} end end - # Use the source handlers to create nodes for the +paths+ in the +tree+. - def create_nodes_from_paths(tree, paths) + # Use the source handlers to create nodes for the +paths+ in the <tt>website.tree</tt>. + def create_nodes_from_paths(paths) used_paths = Set.new website.config['sourcehandler.invoke'].sort.each do |priority, shns| shns.each do |shn| sh = website.cache.instance(shn) handler_paths = paths_for_handler(shn, paths) used_paths.merge(handler_paths) handler_paths.sort {|a,b| a.path.length <=> b.path.length}.each do |path| - parent_dir = path.directory.split('/').collect {|p| Path.new(p).cn}.join('/') - parent_dir += '/' if path != '/' && parent_dir == '' - create_nodes(tree, parent_dir, path, sh) + if !website.tree[path.parent_path] + used_paths.merge(create_nodes_from_paths([path.parent_path])) + end + create_nodes(path, sh) end end end used_paths end - # Prepare everything to create nodes under the absolute lcn path +parent_path_name+ in the - # +tree from the +path+ using the +source_handler+. If a block is given, the actual creation - # of the nodes is deferred to it. After the nodes are created, it is also checked if they have - # all needed properties. - def create_nodes(tree, parent_path_name, path, source_handler) #:yields: parent, path - if !(parent = tree[parent_path_name]) - raise "The specified parent path <#{parent_path_name}> does not exist" - end + # Prepare everything to create from the +path+ using the +source_handler+. If a block is + # given, the actual creation of the nodes is deferred to it. Otherwise the #create_node method + # of the +source_handler+ is used. After the nodes are created, it is also checked if they + # have all needed properties. + def create_nodes(path, source_handler) #:yields: path path = path.dup path.meta_info = default_meta_info(path, source_handler.class.name) (website.cache[:sourcehandler_path_mi] ||= {})[[path.path, source_handler.class.name]] = path.meta_info.dup - website.blackboard.dispatch_msg(:before_node_created, parent, path) + website.blackboard.dispatch_msg(:before_node_created, path) *nodes = if block_given? - yield(parent, path) + yield(path) else - source_handler.create_node(parent, path) + source_handler.create_node(path) end nodes.flatten.compact.each do |node| website.blackboard.dispatch_msg(:after_node_created, node) end nodes