gettalong-webgen 0.5.4.20080929
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.
- data/AUTHORS +5 -0
- data/COPYING +10 -0
- data/GPL +340 -0
- data/Rakefile +324 -0
- data/THANKS +17 -0
- data/bin/webgen +10 -0
- data/data/webgen/resources.yaml +3 -0
- data/data/webgen/webgui/controller/main.rb +129 -0
- data/data/webgen/webgui/overrides/win32console.rb +0 -0
- data/data/webgen/webgui/public/css/jquery.autocomplete.css +50 -0
- data/data/webgen/webgui/public/css/ramaze_error.css +90 -0
- data/data/webgen/webgui/public/css/style.css +55 -0
- data/data/webgen/webgui/public/img/headerbg.jpg +0 -0
- data/data/webgen/webgui/public/img/webgen_logo.png +0 -0
- data/data/webgen/webgui/public/js/jquery.autocomplete.js +15 -0
- data/data/webgen/webgui/public/js/jquery.js +32 -0
- data/data/webgen/webgui/view/create_website.xhtml +22 -0
- data/data/webgen/webgui/view/error.xhtml +64 -0
- data/data/webgen/webgui/view/index.xhtml +22 -0
- data/data/webgen/webgui/view/manage_website.xhtml +18 -0
- data/data/webgen/webgui/view/page.xhtml +40 -0
- data/data/webgen/website_skeleton/README +10 -0
- data/data/webgen/website_skeleton/Rakefile +40 -0
- data/data/webgen/website_skeleton/config.yaml +17 -0
- data/data/webgen/website_skeleton/ext/init.rb +6 -0
- data/data/webgen/website_styles/1024px/README +13 -0
- data/data/webgen/website_styles/1024px/src/default.css +188 -0
- data/data/webgen/website_styles/1024px/src/default.template +60 -0
- data/data/webgen/website_styles/1024px/src/images/background.gif +0 -0
- data/data/webgen/website_styles/andreas00/README +13 -0
- data/data/webgen/website_styles/andreas00/src/default.css +290 -0
- data/data/webgen/website_styles/andreas00/src/default.template +60 -0
- data/data/webgen/website_styles/andreas00/src/images/bg.gif +0 -0
- data/data/webgen/website_styles/andreas00/src/images/front.jpg +0 -0
- data/data/webgen/website_styles/andreas00/src/images/menubg.gif +0 -0
- data/data/webgen/website_styles/andreas00/src/images/menubg2.gif +0 -0
- data/data/webgen/website_styles/andreas01/README +14 -0
- data/data/webgen/website_styles/andreas01/src/default.css +310 -0
- data/data/webgen/website_styles/andreas01/src/default.template +61 -0
- data/data/webgen/website_styles/andreas01/src/images/bg.gif +0 -0
- data/data/webgen/website_styles/andreas01/src/images/front.jpg +0 -0
- data/data/webgen/website_styles/andreas01/src/print.css +35 -0
- data/data/webgen/website_styles/andreas03/README +14 -0
- data/data/webgen/website_styles/andreas03/src/default.css +223 -0
- data/data/webgen/website_styles/andreas03/src/default.template +58 -0
- data/data/webgen/website_styles/andreas03/src/images/bodybg.png +0 -0
- data/data/webgen/website_styles/andreas03/src/images/contbg.png +0 -0
- data/data/webgen/website_styles/andreas03/src/images/footerbg.png +0 -0
- data/data/webgen/website_styles/andreas03/src/images/gradient1.png +0 -0
- data/data/webgen/website_styles/andreas03/src/images/gradient2.png +0 -0
- data/data/webgen/website_styles/andreas04/README +15 -0
- data/data/webgen/website_styles/andreas04/src/default.css +290 -0
- data/data/webgen/website_styles/andreas04/src/default.template +81 -0
- data/data/webgen/website_styles/andreas04/src/images/blinkarrow.gif +0 -0
- data/data/webgen/website_styles/andreas04/src/images/bodybg.png +0 -0
- data/data/webgen/website_styles/andreas04/src/images/contentbg.png +0 -0
- data/data/webgen/website_styles/andreas04/src/images/entrybg.png +0 -0
- data/data/webgen/website_styles/andreas04/src/images/flash.gif +0 -0
- data/data/webgen/website_styles/andreas04/src/images/flash2.gif +0 -0
- data/data/webgen/website_styles/andreas04/src/images/globe.gif +0 -0
- data/data/webgen/website_styles/andreas04/src/images/globebottom.gif +0 -0
- data/data/webgen/website_styles/andreas04/src/images/linkarrow.gif +0 -0
- data/data/webgen/website_styles/andreas04/src/images/menuhover.png +0 -0
- data/data/webgen/website_styles/andreas05/README +14 -0
- data/data/webgen/website_styles/andreas05/src/default.css +33 -0
- data/data/webgen/website_styles/andreas05/src/default.template +40 -0
- data/data/webgen/website_styles/andreas05/src/images/bodybg.gif +0 -0
- data/data/webgen/website_styles/andreas05/src/images/front.png +0 -0
- data/data/webgen/website_styles/andreas06/README +14 -0
- data/data/webgen/website_styles/andreas06/src/default.css +354 -0
- data/data/webgen/website_styles/andreas06/src/default.template +70 -0
- data/data/webgen/website_styles/andreas06/src/images/bodybg.gif +0 -0
- data/data/webgen/website_styles/andreas06/src/images/boxbg.gif +0 -0
- data/data/webgen/website_styles/andreas06/src/images/greypx.gif +0 -0
- data/data/webgen/website_styles/andreas06/src/images/header.jpg +0 -0
- data/data/webgen/website_styles/andreas06/src/images/innerbg.gif +0 -0
- data/data/webgen/website_styles/andreas06/src/images/leaves.jpg +0 -0
- data/data/webgen/website_styles/andreas06/src/images/tabs.gif +0 -0
- data/data/webgen/website_styles/andreas07/README +15 -0
- data/data/webgen/website_styles/andreas07/src/browserfix.css +7 -0
- data/data/webgen/website_styles/andreas07/src/default.css +92 -0
- data/data/webgen/website_styles/andreas07/src/default.template +42 -0
- data/data/webgen/website_styles/andreas07/src/images/bodybg.gif +0 -0
- data/data/webgen/website_styles/andreas07/src/images/sidebarbg.gif +0 -0
- data/data/webgen/website_styles/andreas08/README +14 -0
- data/data/webgen/website_styles/andreas08/src/default.css +224 -0
- data/data/webgen/website_styles/andreas08/src/default.template +51 -0
- data/data/webgen/website_styles/andreas09/README +14 -0
- data/data/webgen/website_styles/andreas09/src/default.css +308 -0
- data/data/webgen/website_styles/andreas09/src/default.template +68 -0
- data/data/webgen/website_styles/andreas09/src/images/bodybg-black.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/bodybg-green.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/bodybg-orange.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/bodybg-purple.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/bodybg-red.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/bodybg.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/footerbg.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/menuhover-black.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/menuhover-green.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/menuhover-orange.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/menuhover-purple.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/menuhover-red.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/menuhover.jpg +0 -0
- data/data/webgen/website_styles/simple/README +6 -0
- data/data/webgen/website_styles/simple/src/default.css +84 -0
- data/data/webgen/website_styles/simple/src/default.template +36 -0
- data/data/webgen/website_templates/default/README +6 -0
- data/data/webgen/website_templates/default/src/index.page +8 -0
- data/data/webgen/website_templates/project/README +5 -0
- data/data/webgen/website_templates/project/src/about.page +12 -0
- data/data/webgen/website_templates/project/src/download.page +15 -0
- data/data/webgen/website_templates/project/src/features.page +8 -0
- data/data/webgen/website_templates/project/src/index.page +9 -0
- data/data/webgen/website_templates/project/src/screenshots.page +18 -0
- data/doc/contentprocessor.template +11 -0
- data/doc/contentprocessor/blocks.page +66 -0
- data/doc/contentprocessor/builder.page +80 -0
- data/doc/contentprocessor/erb.page +56 -0
- data/doc/contentprocessor/erubis.page +46 -0
- data/doc/contentprocessor/haml.page +47 -0
- data/doc/contentprocessor/maruku.page +41 -0
- data/doc/contentprocessor/rdiscount.page +37 -0
- data/doc/contentprocessor/rdoc.page +36 -0
- data/doc/contentprocessor/redcloth.page +39 -0
- data/doc/contentprocessor/sass.page +31 -0
- data/doc/contentprocessor/tags.page +73 -0
- data/doc/extensions.metainfo +29 -0
- data/doc/extensions.page +16 -0
- data/doc/extensions.template +17 -0
- data/doc/faq.page +214 -0
- data/doc/getting_started.page +134 -0
- data/doc/index.page +65 -0
- data/doc/manual.page +532 -0
- data/doc/reference_configuration.page +646 -0
- data/doc/reference_metainfo.page +213 -0
- data/doc/sourcehandler.template +21 -0
- data/doc/sourcehandler/copy.page +19 -0
- data/doc/sourcehandler/directory.page +27 -0
- data/doc/sourcehandler/feed.page +82 -0
- data/doc/sourcehandler/metainfo.page +41 -0
- data/doc/sourcehandler/page.page +30 -0
- data/doc/sourcehandler/sitemap.page +46 -0
- data/doc/sourcehandler/template.page +45 -0
- data/doc/sourcehandler/virtual.page +49 -0
- data/doc/tag.template +25 -0
- data/doc/tag/breadcrumbtrail.page +40 -0
- data/doc/tag/coderay.page +49 -0
- data/doc/tag/date.page +31 -0
- data/doc/tag/executecommand.page +26 -0
- data/doc/tag/includefile.page +32 -0
- data/doc/tag/langbar.page +22 -0
- data/doc/tag/menu.page +92 -0
- data/doc/tag/metainfo.page +29 -0
- data/doc/tag/relocatable.page +38 -0
- data/doc/tag/sitemap.page +31 -0
- data/doc/upgrading.page +139 -0
- data/doc/webgen_page_format.page +128 -0
- data/lib/webgen/blackboard.rb +73 -0
- data/lib/webgen/cache.rb +85 -0
- data/lib/webgen/cli.rb +118 -0
- data/lib/webgen/cli/create_command.rb +64 -0
- data/lib/webgen/cli/run_command.rb +20 -0
- data/lib/webgen/cli/utils.rb +86 -0
- data/lib/webgen/cli/webgui_command.rb +49 -0
- data/lib/webgen/common.rb +10 -0
- data/lib/webgen/common/sitemap.rb +76 -0
- data/lib/webgen/configuration.rb +147 -0
- data/lib/webgen/contentprocessor.rb +96 -0
- data/lib/webgen/contentprocessor/blocks.rb +46 -0
- data/lib/webgen/contentprocessor/builder.rb +26 -0
- data/lib/webgen/contentprocessor/context.rb +90 -0
- data/lib/webgen/contentprocessor/erb.rb +24 -0
- data/lib/webgen/contentprocessor/erubis.rb +40 -0
- data/lib/webgen/contentprocessor/haml.rb +25 -0
- data/lib/webgen/contentprocessor/maruku.rb +18 -0
- data/lib/webgen/contentprocessor/rdiscount.rb +15 -0
- data/lib/webgen/contentprocessor/rdoc.rb +17 -0
- data/lib/webgen/contentprocessor/redcloth.rb +15 -0
- data/lib/webgen/contentprocessor/sass.rb +18 -0
- data/lib/webgen/contentprocessor/tags.rb +134 -0
- data/lib/webgen/coreext.rb +10 -0
- data/lib/webgen/default_config.rb +198 -0
- data/lib/webgen/languages.rb +578 -0
- data/lib/webgen/loggable.rb +23 -0
- data/lib/webgen/logger.rb +78 -0
- data/lib/webgen/node.rb +347 -0
- data/lib/webgen/output.rb +37 -0
- data/lib/webgen/output/filesystem.rb +67 -0
- data/lib/webgen/page.rb +133 -0
- data/lib/webgen/path.rb +182 -0
- data/lib/webgen/source.rb +24 -0
- data/lib/webgen/source/filesystem.rb +58 -0
- data/lib/webgen/source/resource.rb +42 -0
- data/lib/webgen/source/stacked.rb +53 -0
- data/lib/webgen/sourcehandler.rb +202 -0
- data/lib/webgen/sourcehandler/base.rb +211 -0
- data/lib/webgen/sourcehandler/copy.rb +41 -0
- data/lib/webgen/sourcehandler/directory.rb +31 -0
- data/lib/webgen/sourcehandler/feed.rb +121 -0
- data/lib/webgen/sourcehandler/fragment.rb +71 -0
- data/lib/webgen/sourcehandler/metainfo.rb +117 -0
- data/lib/webgen/sourcehandler/page.rb +77 -0
- data/lib/webgen/sourcehandler/sitemap.rb +60 -0
- data/lib/webgen/sourcehandler/template.rb +68 -0
- data/lib/webgen/sourcehandler/virtual.rb +75 -0
- data/lib/webgen/tag.rb +23 -0
- data/lib/webgen/tag/base.rb +162 -0
- data/lib/webgen/tag/breadcrumbtrail.rb +71 -0
- data/lib/webgen/tag/coderay.rb +32 -0
- data/lib/webgen/tag/date.rb +18 -0
- data/lib/webgen/tag/executecommand.rb +29 -0
- data/lib/webgen/tag/includefile.rb +42 -0
- data/lib/webgen/tag/langbar.rb +52 -0
- data/lib/webgen/tag/menu.rb +186 -0
- data/lib/webgen/tag/metainfo.rb +25 -0
- data/lib/webgen/tag/relocatable.rb +53 -0
- data/lib/webgen/tag/sitemap.rb +42 -0
- data/lib/webgen/tree.rb +80 -0
- data/lib/webgen/version.rb +6 -0
- data/lib/webgen/webgentask.rb +148 -0
- data/lib/webgen/website.rb +214 -0
- data/lib/webgen/websiteaccess.rb +29 -0
- data/lib/webgen/websitemanager.rb +125 -0
- data/man/man1/webgen.1 +67 -0
- data/misc/default.css +360 -0
- data/misc/default.template +75 -0
- data/misc/htmldoc.metainfo +25 -0
- data/misc/htmldoc.virtual +5 -0
- data/misc/images/arrow.gif +0 -0
- data/misc/images/error.gif +0 -0
- data/misc/images/exclamation.gif +0 -0
- data/misc/images/headerbg.jpg +0 -0
- data/misc/images/information.gif +0 -0
- data/misc/images/quote.gif +0 -0
- data/setup.rb +1585 -0
- data/test/helper.rb +41 -0
- data/test/test_blackboard.rb +58 -0
- data/test/test_cache.rb +57 -0
- data/test/test_common_sitemap.rb +56 -0
- data/test/test_configuration.rb +66 -0
- data/test/test_contentprocessor.rb +31 -0
- data/test/test_contentprocessor_blocks.rb +34 -0
- data/test/test_contentprocessor_builder.rb +19 -0
- data/test/test_contentprocessor_context.rb +38 -0
- data/test/test_contentprocessor_erb.rb +20 -0
- data/test/test_contentprocessor_erubis.rb +47 -0
- data/test/test_contentprocessor_haml.rb +20 -0
- data/test/test_contentprocessor_maruku.rb +27 -0
- data/test/test_contentprocessor_rdiscount.rb +15 -0
- data/test/test_contentprocessor_rdoc.rb +16 -0
- data/test/test_contentprocessor_redcloth.rb +12 -0
- data/test/test_contentprocessor_sass.rb +20 -0
- data/test/test_contentprocessor_tags.rb +97 -0
- data/test/test_languages.rb +53 -0
- data/test/test_loggable.rb +30 -0
- data/test/test_logger.rb +73 -0
- data/test/test_node.rb +339 -0
- data/test/test_output_filesystem.rb +58 -0
- data/test/test_page.rb +203 -0
- data/test/test_path.rb +131 -0
- data/test/test_source_filesystem.rb +59 -0
- data/test/test_source_resource.rb +26 -0
- data/test/test_source_stacked.rb +34 -0
- data/test/test_sourcehandler_base.rb +92 -0
- data/test/test_sourcehandler_copy.rb +45 -0
- data/test/test_sourcehandler_directory.rb +25 -0
- data/test/test_sourcehandler_feed.rb +74 -0
- data/test/test_sourcehandler_fragment.rb +67 -0
- data/test/test_sourcehandler_metainfo.rb +93 -0
- data/test/test_sourcehandler_page.rb +70 -0
- data/test/test_sourcehandler_sitemap.rb +47 -0
- data/test/test_sourcehandler_template.rb +63 -0
- data/test/test_sourcehandler_virtual.rb +56 -0
- data/test/test_tag_base.rb +82 -0
- data/test/test_tag_breadcrumbtrail.rb +89 -0
- data/test/test_tag_coderay.rb +30 -0
- data/test/test_tag_date.rb +16 -0
- data/test/test_tag_executecommand.rb +39 -0
- data/test/test_tag_includefile.rb +48 -0
- data/test/test_tag_langbar.rb +60 -0
- data/test/test_tag_menu.rb +195 -0
- data/test/test_tag_metainfo.rb +17 -0
- data/test/test_tag_relocatable.rb +57 -0
- data/test/test_tag_sitemap.rb +44 -0
- data/test/test_tree.rb +69 -0
- data/test/test_webgentask.rb +21 -0
- data/test/test_website.rb +96 -0
- data/test/test_websiteaccess.rb +23 -0
- data/test/test_websitemanager.rb +68 -0
- metadata +575 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'webgen/websiteaccess'
|
3
|
+
require 'webgen/path'
|
4
|
+
|
5
|
+
module Webgen
|
6
|
+
|
7
|
+
# This class is used to read source paths from a directory in the file system.
|
8
|
+
class Source::FileSystem
|
9
|
+
|
10
|
+
# A special Webgen::Path class for handling with file system paths.
|
11
|
+
class Path < Webgen::Path
|
12
|
+
|
13
|
+
# Create a new object with absolute path +path+ for the file system path +fs_path+.
|
14
|
+
def initialize(path, fs_path)
|
15
|
+
super(path) { File.open(fs_path, 'rb') }
|
16
|
+
@fs_path = fs_path
|
17
|
+
WebsiteAccess.website.cache[[:fs_path, @fs_path]] = File.mtime(@fs_path)
|
18
|
+
@meta_info['modified_at'] = File.mtime(@fs_path)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Return +true+ if the file system path used by the object has been modified.
|
22
|
+
def changed?
|
23
|
+
data = WebsiteAccess.website.cache[[:fs_path, @fs_path]]
|
24
|
+
File.mtime(@fs_path) > data
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
# The root path from which paths read.
|
30
|
+
attr_reader :root
|
31
|
+
|
32
|
+
# The glob (see Dir.glob for details) that is used to specify which paths under the root path
|
33
|
+
# should be returned by #paths.
|
34
|
+
attr_reader :glob
|
35
|
+
|
36
|
+
# Create a new file system source for the root path +root+ using the provided +glob+.
|
37
|
+
def initialize(root, glob = '**/*')
|
38
|
+
if root =~ /^([a-zA-Z]:|\/)/
|
39
|
+
@root = root
|
40
|
+
else
|
41
|
+
@root = File.join(WebsiteAccess.website.directory, root)
|
42
|
+
end
|
43
|
+
@glob = glob
|
44
|
+
end
|
45
|
+
|
46
|
+
# Return all paths under #root which match #glob.
|
47
|
+
def paths
|
48
|
+
@paths ||= Dir.glob(File.join(@root, @glob), File::FNM_DOTMATCH|File::FNM_CASEFOLD).to_set.collect! do |f|
|
49
|
+
temp = Pathname.new(f.sub(/^#{Regexp.escape(@root)}\/?/, '/')).cleanpath.to_s
|
50
|
+
temp += '/' if File.directory?(f) && temp[-1] != ?/
|
51
|
+
path = Path.new(temp, f)
|
52
|
+
path
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'webgen/websiteaccess'
|
2
|
+
require 'webgen/source'
|
3
|
+
|
4
|
+
module Webgen::Source
|
5
|
+
|
6
|
+
# This class is used to provide access to source provided by resources.
|
7
|
+
class Resource
|
8
|
+
|
9
|
+
include Webgen::WebsiteAccess
|
10
|
+
|
11
|
+
# The glob specifying the resources.
|
12
|
+
attr_reader :glob
|
13
|
+
|
14
|
+
# The glob specifying the paths that should be used from the resources.
|
15
|
+
attr_reader :paths_glob
|
16
|
+
|
17
|
+
# The prefix that should optionally be stripped from the paths.
|
18
|
+
attr_reader :strip_prefix
|
19
|
+
|
20
|
+
# Create a new resource source for the the +glob+ and use only those paths matching +paths_glob+
|
21
|
+
# while stripping +strip_prefix+ off the path.
|
22
|
+
def initialize(glob, paths_glob = nil, strip_prefix = nil)
|
23
|
+
@glob, @paths_glob, @strip_prefix = glob, paths_glob, strip_prefix
|
24
|
+
end
|
25
|
+
|
26
|
+
# Return all paths associated with the resources identified by #glob.
|
27
|
+
def paths
|
28
|
+
if !defined?(@paths)
|
29
|
+
stack = Stacked.new
|
30
|
+
website.config['resources'].select {|name, infos| File.fnmatch(@glob, name)}.sort.each do |name, infos|
|
31
|
+
stack.add([['/', constant(infos.first).new(*infos[1..-1])]])
|
32
|
+
end
|
33
|
+
@paths = stack.paths
|
34
|
+
@paths = @paths.select {|p| File.fnmatch(@paths_glob, p)} if @paths_glob
|
35
|
+
@paths.collect! {|p| p.mount_at('/', @strip_prefix)} if @strip_prefix
|
36
|
+
end
|
37
|
+
@paths
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Webgen::Source
|
2
|
+
|
3
|
+
# This source class is used to stack several sources together.
|
4
|
+
#
|
5
|
+
# It serves two purposes:
|
6
|
+
#
|
7
|
+
# * First, it can be used to access more than one source. This is useful when your website
|
8
|
+
# consists of more than one source directory and you want to use all of them.
|
9
|
+
#
|
10
|
+
# * Second, sources can mounted on specific directories. For example, a folder with images that
|
11
|
+
# you don't want to copy to the website source directory can be mounted under <tt>/images</tt>
|
12
|
+
# sothat they are available nonetheless.
|
13
|
+
#
|
14
|
+
# Also be aware that when a path is returned by a source that has already be returned by a prior
|
15
|
+
# source, it is discarded and not used.
|
16
|
+
class Stacked
|
17
|
+
|
18
|
+
# Return the stack of Webgen::Source objects.
|
19
|
+
attr_reader :stack
|
20
|
+
|
21
|
+
# Create a new stack. The optional +map+ parameter can be used to provide initial mappings of
|
22
|
+
# mount points to source objects (see #add for details).
|
23
|
+
def initialize(map = {})
|
24
|
+
@stack = []
|
25
|
+
add(map)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Add all mappings found in +maps+ to the stack. The parameter +maps+ should be an array of
|
29
|
+
# two-element arrays which contain an absolute directoriy (ie. starting with a slash) and a
|
30
|
+
# source object.
|
31
|
+
def add(maps)
|
32
|
+
maps.each do |mp, source|
|
33
|
+
raise "Invalid mount point specified: #{mp}" unless mp =~ /^\//
|
34
|
+
@stack << [mp, source]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Return all paths returned by the sources in the stack. Since the stack is ordered, paths
|
39
|
+
# returned by later source objects are not used if a prior source object has returned the same
|
40
|
+
# path.
|
41
|
+
def paths
|
42
|
+
@paths = Set.new
|
43
|
+
@stack.each do |mp, source|
|
44
|
+
source.paths.each do |path|
|
45
|
+
@paths.add?(path.mount_at(mp))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
@paths
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,202 @@
|
|
1
|
+
require 'webgen/loggable'
|
2
|
+
require 'benchmark'
|
3
|
+
|
4
|
+
module Webgen
|
5
|
+
|
6
|
+
# Namespace for all classes that handle source paths.
|
7
|
+
#
|
8
|
+
# Have a look at Webgen::SourceHandler::Base for details on how to implement a source handler
|
9
|
+
# class.
|
10
|
+
module SourceHandler
|
11
|
+
|
12
|
+
autoload :Base, 'webgen/sourcehandler/base'
|
13
|
+
autoload :Copy, 'webgen/sourcehandler/copy'
|
14
|
+
autoload :Directory, 'webgen/sourcehandler/directory'
|
15
|
+
autoload :Metainfo, 'webgen/sourcehandler/metainfo'
|
16
|
+
autoload :Template, 'webgen/sourcehandler/template'
|
17
|
+
autoload :Page, 'webgen/sourcehandler/page'
|
18
|
+
autoload :Fragment, 'webgen/sourcehandler/fragment'
|
19
|
+
autoload :Virtual, 'webgen/sourcehandler/virtual'
|
20
|
+
autoload :Feed, 'webgen/sourcehandler/feed'
|
21
|
+
autoload :Sitemap, 'webgen/sourcehandler/sitemap'
|
22
|
+
|
23
|
+
# This class is used by Website to do the actual rendering of the website. It
|
24
|
+
#
|
25
|
+
# * collects all source paths using the source classes
|
26
|
+
# * creates nodes using the source handler classes
|
27
|
+
# * writes changed nodes out using an output class
|
28
|
+
class Main
|
29
|
+
|
30
|
+
include WebsiteAccess
|
31
|
+
include Loggable
|
32
|
+
|
33
|
+
def initialize #:nodoc:
|
34
|
+
website.blackboard.add_service(:create_nodes, method(:create_nodes))
|
35
|
+
website.blackboard.add_service(:source_paths, method(:find_all_source_paths))
|
36
|
+
website.blackboard.add_listener(:node_meta_info_changed?, method(:meta_info_changed?))
|
37
|
+
end
|
38
|
+
|
39
|
+
# Render the nodes provided in the +tree+. Before the actual rendering is done, the sources
|
40
|
+
# are checked (nodes for deleted sources are deleted, nodes for new and changed sources).
|
41
|
+
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)
|
50
|
+
website.cache.reset_volatile_cache
|
51
|
+
end
|
52
|
+
end
|
53
|
+
puts "...done in " + ('%2.4f' % time.real) + ' seconds'
|
54
|
+
|
55
|
+
output = website.blackboard.invoke(:output_instance)
|
56
|
+
|
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
|
79
|
+
end
|
80
|
+
end
|
81
|
+
puts "...done in " + ('%2.4f' % time.real) + ' seconds'
|
82
|
+
end
|
83
|
+
|
84
|
+
#######
|
85
|
+
private
|
86
|
+
#######
|
87
|
+
|
88
|
+
# Return a hash with all source paths.
|
89
|
+
def find_all_source_paths
|
90
|
+
if !defined?(@paths)
|
91
|
+
source = Webgen::Source::Stacked.new(website.config['sources'].collect do |mp, name, *args|
|
92
|
+
[mp, constant(name).new(*args)]
|
93
|
+
end)
|
94
|
+
@paths = {}
|
95
|
+
source.paths.each do |path|
|
96
|
+
if !(website.config['sourcehandler.ignore'].any? {|pat| File.fnmatch(pat, path, File::FNM_CASEFOLD|File::FNM_DOTMATCH)})
|
97
|
+
@paths[path.path] = path
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
@paths
|
102
|
+
end
|
103
|
+
|
104
|
+
# Return only the subset of +paths+ which are handled by the source handler +name+.
|
105
|
+
def paths_for_handler(name, paths)
|
106
|
+
patterns = website.config['sourcehandler.patterns'][name]
|
107
|
+
return [] if patterns.nil?
|
108
|
+
|
109
|
+
options = (website.config['sourcehandler.casefold'] ? File::FNM_CASEFOLD : 0) |
|
110
|
+
(website.config['sourcehandler.use_hidden_files'] ? File::FNM_DOTMATCH : 0)
|
111
|
+
find_all_source_paths.values_at(*paths).select do |path|
|
112
|
+
patterns.any? {|pat| File.fnmatch(pat, path, options)}
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Use the source handlers to create nodes for the +paths+ in the +tree+.
|
117
|
+
def create_nodes_from_paths(tree, paths)
|
118
|
+
website.config['sourcehandler.invoke'].sort.each do |priority, shns|
|
119
|
+
shns.each do |shn|
|
120
|
+
sh = website.cache.instance(shn)
|
121
|
+
paths_for_handler(shn, paths).sort.each do |path|
|
122
|
+
parent_dir = path.directory.split('/').collect {|p| Path.new(p).cn}.join('/')
|
123
|
+
parent_dir += '/' if path != '/' && parent_dir == ''
|
124
|
+
create_nodes(tree, parent_dir, path, sh)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Prepare everything to create nodes under the absolute lcn path +parent_path_name+ in the
|
131
|
+
# +tree from the +path+ using the +source_handler+. If a block is given, the actual creation
|
132
|
+
# of the nodes is deferred to it. After the nodes are created, it is also checked if they have
|
133
|
+
# all needed properties.
|
134
|
+
def create_nodes(tree, parent_path_name, path, source_handler) #:yields: parent, path
|
135
|
+
if !(parent = tree[parent_path_name])
|
136
|
+
raise "The specified parent path <#{parent_path_name}> does not exist"
|
137
|
+
end
|
138
|
+
path = path.dup
|
139
|
+
path.meta_info = default_meta_info(path, source_handler.class.name)
|
140
|
+
(website.cache[:sourcehandler_path_mi] ||= {})[[path.path, source_handler.class.name]] = path.meta_info.dup
|
141
|
+
website.blackboard.dispatch_msg(:before_node_created, parent, path)
|
142
|
+
*nodes = if block_given?
|
143
|
+
yield(parent, path)
|
144
|
+
else
|
145
|
+
source_handler.create_node(parent, path.dup)
|
146
|
+
end
|
147
|
+
nodes.flatten.compact.each do |node|
|
148
|
+
website.blackboard.dispatch_msg(:after_node_created, node)
|
149
|
+
end
|
150
|
+
nodes
|
151
|
+
end
|
152
|
+
|
153
|
+
# Return the default meta info for the pair of +path+ and +sh_name+.
|
154
|
+
def default_meta_info(path, sh_name)
|
155
|
+
path.meta_info.merge(website.config['sourcehandler.default_meta_info'][:all]).
|
156
|
+
merge(website.config['sourcehandler.default_meta_info'][sh_name] || {})
|
157
|
+
end
|
158
|
+
|
159
|
+
# Check if the default meta information for +node+ has changed since the last run. But don't
|
160
|
+
# take the node's path's +modified_at+ meta information into account since that changes on
|
161
|
+
# every path change.
|
162
|
+
def meta_info_changed?(node)
|
163
|
+
path = node.node_info[:src]
|
164
|
+
old_mi = website.cache[:sourcehandler_path_mi][[path, node.node_info[:processor]]]
|
165
|
+
old_mi.delete('modified_at')
|
166
|
+
new_mi = default_meta_info(@paths[path], node.node_info[:processor])
|
167
|
+
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
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
require 'webgen/websiteaccess'
|
2
|
+
require 'webgen/loggable'
|
3
|
+
require 'webgen/page'
|
4
|
+
|
5
|
+
module Webgen::SourceHandler
|
6
|
+
|
7
|
+
# This module should be included in every source handler as it provides the default methods for
|
8
|
+
# creating nodes.
|
9
|
+
#
|
10
|
+
# = Implementing Source Handlers
|
11
|
+
#
|
12
|
+
# A source handler is a webgen extension that processes source paths to create nodes and that
|
13
|
+
# provides the rendered content of these nodes. The nodes are later written to the output
|
14
|
+
# location. This can range from simply copying a path from the source to the output location to
|
15
|
+
# generating a whole set of nodes from one input path!
|
16
|
+
#
|
17
|
+
# The paths that are handled by a source handler are specified via path patterns (see
|
18
|
+
# below). During a webgen run the #create_node method for each source paths that matches a
|
19
|
+
# specified path pattern is called. And when it is time to write out the node, the the #content
|
20
|
+
# method is called to retrieve the rendered content.
|
21
|
+
#
|
22
|
+
# A source handler must not take any parameters on initialization and when this module is not
|
23
|
+
# mixed in, the methods #create_node and #content need to be defined. Also, a source handler does
|
24
|
+
# not need to reside under the Webgen::SourceHandler namespace but all shipped ones do.
|
25
|
+
#
|
26
|
+
# This base class provides useful default implementations of methods that are used by nearly all
|
27
|
+
# source handler class:
|
28
|
+
# * #create_node
|
29
|
+
# * #node_exists?
|
30
|
+
#
|
31
|
+
# It also provides other utility methods:
|
32
|
+
# * #page_from_path
|
33
|
+
# * #content
|
34
|
+
#
|
35
|
+
# = Nodes Created for Paths
|
36
|
+
#
|
37
|
+
# The main functions of a source handler class are to create one or more nodes for a source path
|
38
|
+
# and to provide the content of these nodes. To achieve this, certain information needs to be set
|
39
|
+
# on a node. If you use the methods provided by this base class, you don't need to set them
|
40
|
+
# explicitly because this is done by the provided methods.
|
41
|
+
#
|
42
|
+
# <tt>node_info[:processor]</tt>:: Has to be set to the class name of the source handler. This is
|
43
|
+
# used by the Node class: all unknown method calls are forwarded
|
44
|
+
# to the node processor.
|
45
|
+
# <tt>node_info[:src]</tt>:: Has to be set to the string version of the source path.
|
46
|
+
# <tt>meta_info['no_output']</tt>:: Has to be set to +true+ on nodes that are used during a
|
47
|
+
# webgen run but do not produce an output file.
|
48
|
+
#
|
49
|
+
# Additional information that is used only for processing purposes should be stored in the
|
50
|
+
# #node_info hash of a node as the #meta_info hash is reserved for real node meta information and
|
51
|
+
# should not be changed once the node is created.
|
52
|
+
#
|
53
|
+
# = Path Patterns and Invocation order
|
54
|
+
#
|
55
|
+
# Path patterns define which paths are handled by a specific source handler. These patterns are
|
56
|
+
# specified in the <tt>sourcehandler.patterns</tt> configuration hash as a mapping from the source
|
57
|
+
# handler class name to an array of path patterns. The patterns need to have a format that
|
58
|
+
# <tt>Dir.glob</tt> can handle.
|
59
|
+
#
|
60
|
+
# Specifying a path pattern does not mean that webgen uses the source handler. One also needs to
|
61
|
+
# provide an entry in the configuration value <tt>sourcehandler.invoke</tt>. This is a hash that
|
62
|
+
# maps the invocation rank (a number) to an array of source handler class names. The lower the
|
63
|
+
# invocation rank the earlier the specified source handlers are used.
|
64
|
+
#
|
65
|
+
# The default invocation ranks are:
|
66
|
+
# 1:: Early. Normally there is no need to use this rank.
|
67
|
+
# 5:: Standard. This is the rank the normal source handler should use.
|
68
|
+
# 9:: Late. This rank should be used by source handlers that operate on/use already created nodes
|
69
|
+
# and need to ensure that these nodes are available.
|
70
|
+
#
|
71
|
+
# = Default Meta Information
|
72
|
+
#
|
73
|
+
# Each source handler can define default meta information that gets automatically set on the
|
74
|
+
# source paths that are passed to the #create_node method.
|
75
|
+
#
|
76
|
+
# The default meta information is specified in the <tt>sourcehandler.default_meta_info</tt>
|
77
|
+
# configuration hash as a mapping from the source handler class name to the meta information
|
78
|
+
# hash.
|
79
|
+
#
|
80
|
+
# = Sample Source Handler Class
|
81
|
+
#
|
82
|
+
# Following is a simple source handler class example which copies paths from the source to
|
83
|
+
# the output location modifying the extension:
|
84
|
+
#
|
85
|
+
# class SimpleCopy
|
86
|
+
#
|
87
|
+
# include Webgen::SourceHandler::Base
|
88
|
+
#
|
89
|
+
# def create_node(parent, path)
|
90
|
+
# path.ext += '.copied'
|
91
|
+
# super(parent, path)
|
92
|
+
# end
|
93
|
+
#
|
94
|
+
# def content(node)
|
95
|
+
# website.blackboard.invoke(:source_paths)[node.node_info[:src]].io
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# end
|
99
|
+
#
|
100
|
+
# WebsiteAccess.website.config.sourcehandler.patterns['SimpleCopy'] = ['**/*.jpg', '**/*.png']
|
101
|
+
# WebsiteAccess.website.config.sourcehandler.invoke[5] << 'SimpleCopy'
|
102
|
+
#
|
103
|
+
module Base
|
104
|
+
|
105
|
+
# This module is used for defining all methods that can be used for creating output paths.
|
106
|
+
#
|
107
|
+
# All public methods of this module are considered to be output path creation methods and must
|
108
|
+
# have the following parameters:
|
109
|
+
# +parent+:: the parent node
|
110
|
+
# +path+:: the path for which the output name should be created
|
111
|
+
# +use_lang_part+:: controls whether the output path name has to include the language part
|
112
|
+
module OutputPathHelpers
|
113
|
+
|
114
|
+
# Default method for creating an output path for +parent+ and source +path+.
|
115
|
+
#
|
116
|
+
# The automatically set parameter +style+ (which uses the meta information +output_path_style+
|
117
|
+
# from the path's meta information hash) defines how the output name should be built (more
|
118
|
+
# information about this in the user documentation).
|
119
|
+
def standard_output_path(parent, path, use_lang_part, style = path.meta_info['output_path_style'])
|
120
|
+
result = style.collect do |part|
|
121
|
+
case part
|
122
|
+
when String then part
|
123
|
+
when :lang then use_lang_part ? path.meta_info['lang'] : ''
|
124
|
+
when :ext then path.ext.empty? ? '' : '.' + path.ext
|
125
|
+
when :parent then temp = parent; temp = temp.parent while temp.is_fragment?; temp.path
|
126
|
+
when :year, :month, :day
|
127
|
+
ctime = path.meta_info['created_at']
|
128
|
+
if !ctime.kind_of?(Time)
|
129
|
+
raise "Invalid meta info 'created_at' for #{path}, needed because of used output path style"
|
130
|
+
end
|
131
|
+
ctime.send(part).to_s.rjust(2, '0')
|
132
|
+
when Symbol then path.send(part)
|
133
|
+
when Array then part.include?(:lang) && !use_lang_part ? '' : standard_output_path(parent, path, use_lang_part, part)
|
134
|
+
else ''
|
135
|
+
end
|
136
|
+
end
|
137
|
+
result.join('')
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
include Webgen::Loggable
|
143
|
+
include OutputPathHelpers
|
144
|
+
|
145
|
+
# Construct the output name for the given +path+ and +parent+. First it is checked if a node
|
146
|
+
# with the constructed output name already exists. If it exists, the language part is forced to
|
147
|
+
# be in the output name and the resulting output name is returned.
|
148
|
+
def output_path(parent, path)
|
149
|
+
method = path.meta_info['output_path'] + '_output_path'
|
150
|
+
use_lang_part = if path.meta_info['lang'].nil? # unlocalized files never get a lang in the filename!
|
151
|
+
false
|
152
|
+
else
|
153
|
+
Webgen::WebsiteAccess.website.config['sourcehandler.default_lang_in_output_path'] ||
|
154
|
+
Webgen::WebsiteAccess.website.config['website.lang'] != path.meta_info['lang']
|
155
|
+
end
|
156
|
+
if OutputPathHelpers.public_instance_methods(false).include?(method)
|
157
|
+
name = send(method, parent, path, use_lang_part)
|
158
|
+
name += '/' if path.path =~ /\/$/ && name !~ /\/$/
|
159
|
+
if node_exists?(parent, path, name)
|
160
|
+
name = send(method, parent, path, (path.meta_info['lang'].nil? ? false : true))
|
161
|
+
name += '/' if path.path =~ /\/$/ && name !~ /\/$/
|
162
|
+
end
|
163
|
+
name
|
164
|
+
else
|
165
|
+
raise "Unknown method for creating output path: #{method}"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# Check if the node alcn and output path which would be created by #create_node exists. The
|
170
|
+
# +output_path+ to check for can individually be set.
|
171
|
+
def node_exists?(parent, path, output_path = self.output_path(parent, path))
|
172
|
+
parent.tree[Webgen::Node.absolute_name(parent, path.lcn, :alcn)] || (!path.meta_info['no_output'] && parent.tree[output_path, :path])
|
173
|
+
end
|
174
|
+
|
175
|
+
# Create and return a node under +parent+ from +path+ if it does not already exists. Some
|
176
|
+
# additional node information like <tt>:src</tt> and <tt>:processor</tt> is set and the meta
|
177
|
+
# information is checked for validness. The created node is yielded if a block is given.
|
178
|
+
def create_node(parent, path, output_path = self.output_path(parent, path))
|
179
|
+
return if path.meta_info['draft']
|
180
|
+
if !node_exists?(parent, path, output_path)
|
181
|
+
node = Webgen::Node.new(parent, output_path, path.cn, path.meta_info)
|
182
|
+
node['modified_at'] = Time.now unless node['modified_at'].kind_of?(Time)
|
183
|
+
node.node_info[:src] = path.path
|
184
|
+
node.node_info[:processor] = self.class.name
|
185
|
+
yield(node) if block_given?
|
186
|
+
node
|
187
|
+
else
|
188
|
+
log(:warn) { "Node already exists: output path = #{output_path} | alcn = #{Webgen::Node.absolute_name(parent, path.lcn, :alcn)}"}
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# Return the content of the given +node+. This default +content+ method just returns +nil+.
|
193
|
+
def content(node)
|
194
|
+
nil
|
195
|
+
end
|
196
|
+
|
197
|
+
# Utility method for creating a Webgen::Page object from the +path+. Also updates
|
198
|
+
# <tt>path.meta_info</tt> with the meta info from the page.
|
199
|
+
def page_from_path(path)
|
200
|
+
begin
|
201
|
+
page = Webgen::Page.from_data(path.io.data, path.meta_info)
|
202
|
+
rescue Webgen::WebgenPageFormatError => e
|
203
|
+
raise "Error reading source path <#{path}>: #{e.message}"
|
204
|
+
end
|
205
|
+
path.meta_info = page.meta_info
|
206
|
+
page
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|