gettalong-webgen 0.5.4.20080929

Sign up to get free protection for your applications and to get access to all the features.
Files changed (290) hide show
  1. data/AUTHORS +5 -0
  2. data/COPYING +10 -0
  3. data/GPL +340 -0
  4. data/Rakefile +324 -0
  5. data/THANKS +17 -0
  6. data/bin/webgen +10 -0
  7. data/data/webgen/resources.yaml +3 -0
  8. data/data/webgen/webgui/controller/main.rb +129 -0
  9. data/data/webgen/webgui/overrides/win32console.rb +0 -0
  10. data/data/webgen/webgui/public/css/jquery.autocomplete.css +50 -0
  11. data/data/webgen/webgui/public/css/ramaze_error.css +90 -0
  12. data/data/webgen/webgui/public/css/style.css +55 -0
  13. data/data/webgen/webgui/public/img/headerbg.jpg +0 -0
  14. data/data/webgen/webgui/public/img/webgen_logo.png +0 -0
  15. data/data/webgen/webgui/public/js/jquery.autocomplete.js +15 -0
  16. data/data/webgen/webgui/public/js/jquery.js +32 -0
  17. data/data/webgen/webgui/view/create_website.xhtml +22 -0
  18. data/data/webgen/webgui/view/error.xhtml +64 -0
  19. data/data/webgen/webgui/view/index.xhtml +22 -0
  20. data/data/webgen/webgui/view/manage_website.xhtml +18 -0
  21. data/data/webgen/webgui/view/page.xhtml +40 -0
  22. data/data/webgen/website_skeleton/README +10 -0
  23. data/data/webgen/website_skeleton/Rakefile +40 -0
  24. data/data/webgen/website_skeleton/config.yaml +17 -0
  25. data/data/webgen/website_skeleton/ext/init.rb +6 -0
  26. data/data/webgen/website_styles/1024px/README +13 -0
  27. data/data/webgen/website_styles/1024px/src/default.css +188 -0
  28. data/data/webgen/website_styles/1024px/src/default.template +60 -0
  29. data/data/webgen/website_styles/1024px/src/images/background.gif +0 -0
  30. data/data/webgen/website_styles/andreas00/README +13 -0
  31. data/data/webgen/website_styles/andreas00/src/default.css +290 -0
  32. data/data/webgen/website_styles/andreas00/src/default.template +60 -0
  33. data/data/webgen/website_styles/andreas00/src/images/bg.gif +0 -0
  34. data/data/webgen/website_styles/andreas00/src/images/front.jpg +0 -0
  35. data/data/webgen/website_styles/andreas00/src/images/menubg.gif +0 -0
  36. data/data/webgen/website_styles/andreas00/src/images/menubg2.gif +0 -0
  37. data/data/webgen/website_styles/andreas01/README +14 -0
  38. data/data/webgen/website_styles/andreas01/src/default.css +310 -0
  39. data/data/webgen/website_styles/andreas01/src/default.template +61 -0
  40. data/data/webgen/website_styles/andreas01/src/images/bg.gif +0 -0
  41. data/data/webgen/website_styles/andreas01/src/images/front.jpg +0 -0
  42. data/data/webgen/website_styles/andreas01/src/print.css +35 -0
  43. data/data/webgen/website_styles/andreas03/README +14 -0
  44. data/data/webgen/website_styles/andreas03/src/default.css +223 -0
  45. data/data/webgen/website_styles/andreas03/src/default.template +58 -0
  46. data/data/webgen/website_styles/andreas03/src/images/bodybg.png +0 -0
  47. data/data/webgen/website_styles/andreas03/src/images/contbg.png +0 -0
  48. data/data/webgen/website_styles/andreas03/src/images/footerbg.png +0 -0
  49. data/data/webgen/website_styles/andreas03/src/images/gradient1.png +0 -0
  50. data/data/webgen/website_styles/andreas03/src/images/gradient2.png +0 -0
  51. data/data/webgen/website_styles/andreas04/README +15 -0
  52. data/data/webgen/website_styles/andreas04/src/default.css +290 -0
  53. data/data/webgen/website_styles/andreas04/src/default.template +81 -0
  54. data/data/webgen/website_styles/andreas04/src/images/blinkarrow.gif +0 -0
  55. data/data/webgen/website_styles/andreas04/src/images/bodybg.png +0 -0
  56. data/data/webgen/website_styles/andreas04/src/images/contentbg.png +0 -0
  57. data/data/webgen/website_styles/andreas04/src/images/entrybg.png +0 -0
  58. data/data/webgen/website_styles/andreas04/src/images/flash.gif +0 -0
  59. data/data/webgen/website_styles/andreas04/src/images/flash2.gif +0 -0
  60. data/data/webgen/website_styles/andreas04/src/images/globe.gif +0 -0
  61. data/data/webgen/website_styles/andreas04/src/images/globebottom.gif +0 -0
  62. data/data/webgen/website_styles/andreas04/src/images/linkarrow.gif +0 -0
  63. data/data/webgen/website_styles/andreas04/src/images/menuhover.png +0 -0
  64. data/data/webgen/website_styles/andreas05/README +14 -0
  65. data/data/webgen/website_styles/andreas05/src/default.css +33 -0
  66. data/data/webgen/website_styles/andreas05/src/default.template +40 -0
  67. data/data/webgen/website_styles/andreas05/src/images/bodybg.gif +0 -0
  68. data/data/webgen/website_styles/andreas05/src/images/front.png +0 -0
  69. data/data/webgen/website_styles/andreas06/README +14 -0
  70. data/data/webgen/website_styles/andreas06/src/default.css +354 -0
  71. data/data/webgen/website_styles/andreas06/src/default.template +70 -0
  72. data/data/webgen/website_styles/andreas06/src/images/bodybg.gif +0 -0
  73. data/data/webgen/website_styles/andreas06/src/images/boxbg.gif +0 -0
  74. data/data/webgen/website_styles/andreas06/src/images/greypx.gif +0 -0
  75. data/data/webgen/website_styles/andreas06/src/images/header.jpg +0 -0
  76. data/data/webgen/website_styles/andreas06/src/images/innerbg.gif +0 -0
  77. data/data/webgen/website_styles/andreas06/src/images/leaves.jpg +0 -0
  78. data/data/webgen/website_styles/andreas06/src/images/tabs.gif +0 -0
  79. data/data/webgen/website_styles/andreas07/README +15 -0
  80. data/data/webgen/website_styles/andreas07/src/browserfix.css +7 -0
  81. data/data/webgen/website_styles/andreas07/src/default.css +92 -0
  82. data/data/webgen/website_styles/andreas07/src/default.template +42 -0
  83. data/data/webgen/website_styles/andreas07/src/images/bodybg.gif +0 -0
  84. data/data/webgen/website_styles/andreas07/src/images/sidebarbg.gif +0 -0
  85. data/data/webgen/website_styles/andreas08/README +14 -0
  86. data/data/webgen/website_styles/andreas08/src/default.css +224 -0
  87. data/data/webgen/website_styles/andreas08/src/default.template +51 -0
  88. data/data/webgen/website_styles/andreas09/README +14 -0
  89. data/data/webgen/website_styles/andreas09/src/default.css +308 -0
  90. data/data/webgen/website_styles/andreas09/src/default.template +68 -0
  91. data/data/webgen/website_styles/andreas09/src/images/bodybg-black.jpg +0 -0
  92. data/data/webgen/website_styles/andreas09/src/images/bodybg-green.jpg +0 -0
  93. data/data/webgen/website_styles/andreas09/src/images/bodybg-orange.jpg +0 -0
  94. data/data/webgen/website_styles/andreas09/src/images/bodybg-purple.jpg +0 -0
  95. data/data/webgen/website_styles/andreas09/src/images/bodybg-red.jpg +0 -0
  96. data/data/webgen/website_styles/andreas09/src/images/bodybg.jpg +0 -0
  97. data/data/webgen/website_styles/andreas09/src/images/footerbg.jpg +0 -0
  98. data/data/webgen/website_styles/andreas09/src/images/menuhover-black.jpg +0 -0
  99. data/data/webgen/website_styles/andreas09/src/images/menuhover-green.jpg +0 -0
  100. data/data/webgen/website_styles/andreas09/src/images/menuhover-orange.jpg +0 -0
  101. data/data/webgen/website_styles/andreas09/src/images/menuhover-purple.jpg +0 -0
  102. data/data/webgen/website_styles/andreas09/src/images/menuhover-red.jpg +0 -0
  103. data/data/webgen/website_styles/andreas09/src/images/menuhover.jpg +0 -0
  104. data/data/webgen/website_styles/simple/README +6 -0
  105. data/data/webgen/website_styles/simple/src/default.css +84 -0
  106. data/data/webgen/website_styles/simple/src/default.template +36 -0
  107. data/data/webgen/website_templates/default/README +6 -0
  108. data/data/webgen/website_templates/default/src/index.page +8 -0
  109. data/data/webgen/website_templates/project/README +5 -0
  110. data/data/webgen/website_templates/project/src/about.page +12 -0
  111. data/data/webgen/website_templates/project/src/download.page +15 -0
  112. data/data/webgen/website_templates/project/src/features.page +8 -0
  113. data/data/webgen/website_templates/project/src/index.page +9 -0
  114. data/data/webgen/website_templates/project/src/screenshots.page +18 -0
  115. data/doc/contentprocessor.template +11 -0
  116. data/doc/contentprocessor/blocks.page +66 -0
  117. data/doc/contentprocessor/builder.page +80 -0
  118. data/doc/contentprocessor/erb.page +56 -0
  119. data/doc/contentprocessor/erubis.page +46 -0
  120. data/doc/contentprocessor/haml.page +47 -0
  121. data/doc/contentprocessor/maruku.page +41 -0
  122. data/doc/contentprocessor/rdiscount.page +37 -0
  123. data/doc/contentprocessor/rdoc.page +36 -0
  124. data/doc/contentprocessor/redcloth.page +39 -0
  125. data/doc/contentprocessor/sass.page +31 -0
  126. data/doc/contentprocessor/tags.page +73 -0
  127. data/doc/extensions.metainfo +29 -0
  128. data/doc/extensions.page +16 -0
  129. data/doc/extensions.template +17 -0
  130. data/doc/faq.page +214 -0
  131. data/doc/getting_started.page +134 -0
  132. data/doc/index.page +65 -0
  133. data/doc/manual.page +532 -0
  134. data/doc/reference_configuration.page +646 -0
  135. data/doc/reference_metainfo.page +213 -0
  136. data/doc/sourcehandler.template +21 -0
  137. data/doc/sourcehandler/copy.page +19 -0
  138. data/doc/sourcehandler/directory.page +27 -0
  139. data/doc/sourcehandler/feed.page +82 -0
  140. data/doc/sourcehandler/metainfo.page +41 -0
  141. data/doc/sourcehandler/page.page +30 -0
  142. data/doc/sourcehandler/sitemap.page +46 -0
  143. data/doc/sourcehandler/template.page +45 -0
  144. data/doc/sourcehandler/virtual.page +49 -0
  145. data/doc/tag.template +25 -0
  146. data/doc/tag/breadcrumbtrail.page +40 -0
  147. data/doc/tag/coderay.page +49 -0
  148. data/doc/tag/date.page +31 -0
  149. data/doc/tag/executecommand.page +26 -0
  150. data/doc/tag/includefile.page +32 -0
  151. data/doc/tag/langbar.page +22 -0
  152. data/doc/tag/menu.page +92 -0
  153. data/doc/tag/metainfo.page +29 -0
  154. data/doc/tag/relocatable.page +38 -0
  155. data/doc/tag/sitemap.page +31 -0
  156. data/doc/upgrading.page +139 -0
  157. data/doc/webgen_page_format.page +128 -0
  158. data/lib/webgen/blackboard.rb +73 -0
  159. data/lib/webgen/cache.rb +85 -0
  160. data/lib/webgen/cli.rb +118 -0
  161. data/lib/webgen/cli/create_command.rb +64 -0
  162. data/lib/webgen/cli/run_command.rb +20 -0
  163. data/lib/webgen/cli/utils.rb +86 -0
  164. data/lib/webgen/cli/webgui_command.rb +49 -0
  165. data/lib/webgen/common.rb +10 -0
  166. data/lib/webgen/common/sitemap.rb +76 -0
  167. data/lib/webgen/configuration.rb +147 -0
  168. data/lib/webgen/contentprocessor.rb +96 -0
  169. data/lib/webgen/contentprocessor/blocks.rb +46 -0
  170. data/lib/webgen/contentprocessor/builder.rb +26 -0
  171. data/lib/webgen/contentprocessor/context.rb +90 -0
  172. data/lib/webgen/contentprocessor/erb.rb +24 -0
  173. data/lib/webgen/contentprocessor/erubis.rb +40 -0
  174. data/lib/webgen/contentprocessor/haml.rb +25 -0
  175. data/lib/webgen/contentprocessor/maruku.rb +18 -0
  176. data/lib/webgen/contentprocessor/rdiscount.rb +15 -0
  177. data/lib/webgen/contentprocessor/rdoc.rb +17 -0
  178. data/lib/webgen/contentprocessor/redcloth.rb +15 -0
  179. data/lib/webgen/contentprocessor/sass.rb +18 -0
  180. data/lib/webgen/contentprocessor/tags.rb +134 -0
  181. data/lib/webgen/coreext.rb +10 -0
  182. data/lib/webgen/default_config.rb +198 -0
  183. data/lib/webgen/languages.rb +578 -0
  184. data/lib/webgen/loggable.rb +23 -0
  185. data/lib/webgen/logger.rb +78 -0
  186. data/lib/webgen/node.rb +347 -0
  187. data/lib/webgen/output.rb +37 -0
  188. data/lib/webgen/output/filesystem.rb +67 -0
  189. data/lib/webgen/page.rb +133 -0
  190. data/lib/webgen/path.rb +182 -0
  191. data/lib/webgen/source.rb +24 -0
  192. data/lib/webgen/source/filesystem.rb +58 -0
  193. data/lib/webgen/source/resource.rb +42 -0
  194. data/lib/webgen/source/stacked.rb +53 -0
  195. data/lib/webgen/sourcehandler.rb +202 -0
  196. data/lib/webgen/sourcehandler/base.rb +211 -0
  197. data/lib/webgen/sourcehandler/copy.rb +41 -0
  198. data/lib/webgen/sourcehandler/directory.rb +31 -0
  199. data/lib/webgen/sourcehandler/feed.rb +121 -0
  200. data/lib/webgen/sourcehandler/fragment.rb +71 -0
  201. data/lib/webgen/sourcehandler/metainfo.rb +117 -0
  202. data/lib/webgen/sourcehandler/page.rb +77 -0
  203. data/lib/webgen/sourcehandler/sitemap.rb +60 -0
  204. data/lib/webgen/sourcehandler/template.rb +68 -0
  205. data/lib/webgen/sourcehandler/virtual.rb +75 -0
  206. data/lib/webgen/tag.rb +23 -0
  207. data/lib/webgen/tag/base.rb +162 -0
  208. data/lib/webgen/tag/breadcrumbtrail.rb +71 -0
  209. data/lib/webgen/tag/coderay.rb +32 -0
  210. data/lib/webgen/tag/date.rb +18 -0
  211. data/lib/webgen/tag/executecommand.rb +29 -0
  212. data/lib/webgen/tag/includefile.rb +42 -0
  213. data/lib/webgen/tag/langbar.rb +52 -0
  214. data/lib/webgen/tag/menu.rb +186 -0
  215. data/lib/webgen/tag/metainfo.rb +25 -0
  216. data/lib/webgen/tag/relocatable.rb +53 -0
  217. data/lib/webgen/tag/sitemap.rb +42 -0
  218. data/lib/webgen/tree.rb +80 -0
  219. data/lib/webgen/version.rb +6 -0
  220. data/lib/webgen/webgentask.rb +148 -0
  221. data/lib/webgen/website.rb +214 -0
  222. data/lib/webgen/websiteaccess.rb +29 -0
  223. data/lib/webgen/websitemanager.rb +125 -0
  224. data/man/man1/webgen.1 +67 -0
  225. data/misc/default.css +360 -0
  226. data/misc/default.template +75 -0
  227. data/misc/htmldoc.metainfo +25 -0
  228. data/misc/htmldoc.virtual +5 -0
  229. data/misc/images/arrow.gif +0 -0
  230. data/misc/images/error.gif +0 -0
  231. data/misc/images/exclamation.gif +0 -0
  232. data/misc/images/headerbg.jpg +0 -0
  233. data/misc/images/information.gif +0 -0
  234. data/misc/images/quote.gif +0 -0
  235. data/setup.rb +1585 -0
  236. data/test/helper.rb +41 -0
  237. data/test/test_blackboard.rb +58 -0
  238. data/test/test_cache.rb +57 -0
  239. data/test/test_common_sitemap.rb +56 -0
  240. data/test/test_configuration.rb +66 -0
  241. data/test/test_contentprocessor.rb +31 -0
  242. data/test/test_contentprocessor_blocks.rb +34 -0
  243. data/test/test_contentprocessor_builder.rb +19 -0
  244. data/test/test_contentprocessor_context.rb +38 -0
  245. data/test/test_contentprocessor_erb.rb +20 -0
  246. data/test/test_contentprocessor_erubis.rb +47 -0
  247. data/test/test_contentprocessor_haml.rb +20 -0
  248. data/test/test_contentprocessor_maruku.rb +27 -0
  249. data/test/test_contentprocessor_rdiscount.rb +15 -0
  250. data/test/test_contentprocessor_rdoc.rb +16 -0
  251. data/test/test_contentprocessor_redcloth.rb +12 -0
  252. data/test/test_contentprocessor_sass.rb +20 -0
  253. data/test/test_contentprocessor_tags.rb +97 -0
  254. data/test/test_languages.rb +53 -0
  255. data/test/test_loggable.rb +30 -0
  256. data/test/test_logger.rb +73 -0
  257. data/test/test_node.rb +339 -0
  258. data/test/test_output_filesystem.rb +58 -0
  259. data/test/test_page.rb +203 -0
  260. data/test/test_path.rb +131 -0
  261. data/test/test_source_filesystem.rb +59 -0
  262. data/test/test_source_resource.rb +26 -0
  263. data/test/test_source_stacked.rb +34 -0
  264. data/test/test_sourcehandler_base.rb +92 -0
  265. data/test/test_sourcehandler_copy.rb +45 -0
  266. data/test/test_sourcehandler_directory.rb +25 -0
  267. data/test/test_sourcehandler_feed.rb +74 -0
  268. data/test/test_sourcehandler_fragment.rb +67 -0
  269. data/test/test_sourcehandler_metainfo.rb +93 -0
  270. data/test/test_sourcehandler_page.rb +70 -0
  271. data/test/test_sourcehandler_sitemap.rb +47 -0
  272. data/test/test_sourcehandler_template.rb +63 -0
  273. data/test/test_sourcehandler_virtual.rb +56 -0
  274. data/test/test_tag_base.rb +82 -0
  275. data/test/test_tag_breadcrumbtrail.rb +89 -0
  276. data/test/test_tag_coderay.rb +30 -0
  277. data/test/test_tag_date.rb +16 -0
  278. data/test/test_tag_executecommand.rb +39 -0
  279. data/test/test_tag_includefile.rb +48 -0
  280. data/test/test_tag_langbar.rb +60 -0
  281. data/test/test_tag_menu.rb +195 -0
  282. data/test/test_tag_metainfo.rb +17 -0
  283. data/test/test_tag_relocatable.rb +57 -0
  284. data/test/test_tag_sitemap.rb +44 -0
  285. data/test/test_tree.rb +69 -0
  286. data/test/test_webgentask.rb +21 -0
  287. data/test/test_website.rb +96 -0
  288. data/test/test_websiteaccess.rb +23 -0
  289. data/test/test_websitemanager.rb +68 -0
  290. 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