ruwiki 0.9.0

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 (96) hide show
  1. data/Readme.rubygems +86 -0
  2. data/Readme.tarfile +65 -0
  3. data/bin/ruwiki +58 -0
  4. data/bin/ruwiki.cgi +87 -0
  5. data/bin/ruwiki_convert +56 -0
  6. data/bin/ruwiki_service.rb +82 -0
  7. data/bin/ruwiki_servlet +53 -0
  8. data/contrib/enscript-token.rb +55 -0
  9. data/contrib/rublog_integrator.rb +68 -0
  10. data/data/Default/ProjectIndex.ruwiki +49 -0
  11. data/data/Ruwiki/Antispam.ruwiki +65 -0
  12. data/data/Ruwiki/BugTracking.ruwiki +33 -0
  13. data/data/Ruwiki/ChangeLog.ruwiki +102 -0
  14. data/data/Ruwiki/Configuring_Ruwiki.ruwiki +151 -0
  15. data/data/Ruwiki/Extending_Ruwiki.ruwiki +317 -0
  16. data/data/Ruwiki/LicenseAndAuthorInfo.ruwiki +30 -0
  17. data/data/Ruwiki/ProjectIndex.ruwiki +84 -0
  18. data/data/Ruwiki/Roadmap.ruwiki +225 -0
  19. data/data/Ruwiki/RuwikiTemplatingLibrary.ruwiki +156 -0
  20. data/data/Ruwiki/RuwikiUtilities.ruwiki +157 -0
  21. data/data/Ruwiki/SandBox.ruwiki +9 -0
  22. data/data/Ruwiki/To_Do.ruwiki +51 -0
  23. data/data/Ruwiki/TroubleShooting.ruwiki +33 -0
  24. data/data/Ruwiki/WikiFeatures.ruwiki +17 -0
  25. data/data/Ruwiki/WikiMarkup.ruwiki +261 -0
  26. data/data/Tutorial/AddingPages.ruwiki +16 -0
  27. data/data/Tutorial/AddingProjects.ruwiki +16 -0
  28. data/data/Tutorial/ProjectIndex.ruwiki +11 -0
  29. data/data/Tutorial/SandBox.ruwiki +9 -0
  30. data/data/agents.banned +60 -0
  31. data/data/agents.readonly +321 -0
  32. data/data/hostip.banned +30 -0
  33. data/data/hostip.readonly +28 -0
  34. data/lib/ruwiki.rb +622 -0
  35. data/lib/ruwiki/auth.rb +56 -0
  36. data/lib/ruwiki/auth/gforge.rb +73 -0
  37. data/lib/ruwiki/backend.rb +318 -0
  38. data/lib/ruwiki/backend/flatfiles.rb +217 -0
  39. data/lib/ruwiki/config.rb +244 -0
  40. data/lib/ruwiki/exportable.rb +192 -0
  41. data/lib/ruwiki/handler.rb +342 -0
  42. data/lib/ruwiki/lang/de.rb +339 -0
  43. data/lib/ruwiki/lang/en.rb +334 -0
  44. data/lib/ruwiki/lang/es.rb +339 -0
  45. data/lib/ruwiki/page.rb +262 -0
  46. data/lib/ruwiki/servlet.rb +38 -0
  47. data/lib/ruwiki/template.rb +553 -0
  48. data/lib/ruwiki/utils.rb +24 -0
  49. data/lib/ruwiki/utils/command.rb +102 -0
  50. data/lib/ruwiki/utils/converter.rb +297 -0
  51. data/lib/ruwiki/utils/manager.rb +639 -0
  52. data/lib/ruwiki/utils/servletrunner.rb +295 -0
  53. data/lib/ruwiki/wiki.rb +147 -0
  54. data/lib/ruwiki/wiki/tokens.rb +136 -0
  55. data/lib/ruwiki/wiki/tokens/00default.rb +211 -0
  56. data/lib/ruwiki/wiki/tokens/01wikilinks.rb +166 -0
  57. data/lib/ruwiki/wiki/tokens/02actions.rb +63 -0
  58. data/lib/ruwiki/wiki/tokens/abbreviations.rb +40 -0
  59. data/lib/ruwiki/wiki/tokens/calendar.rb +147 -0
  60. data/lib/ruwiki/wiki/tokens/headings.rb +43 -0
  61. data/lib/ruwiki/wiki/tokens/lists.rb +112 -0
  62. data/lib/ruwiki/wiki/tokens/rubylists.rb +48 -0
  63. data/ruwiki.conf +22 -0
  64. data/ruwiki.pkg +0 -0
  65. data/templates/default/body.tmpl +19 -0
  66. data/templates/default/content.tmpl +7 -0
  67. data/templates/default/controls.tmpl +23 -0
  68. data/templates/default/edit.tmpl +27 -0
  69. data/templates/default/error.tmpl +14 -0
  70. data/templates/default/footer.tmpl +23 -0
  71. data/templates/default/ruwiki.css +297 -0
  72. data/templates/default/save.tmpl +8 -0
  73. data/templates/sidebar/body.tmpl +19 -0
  74. data/templates/sidebar/content.tmpl +8 -0
  75. data/templates/sidebar/controls.tmpl +8 -0
  76. data/templates/sidebar/edit.tmpl +27 -0
  77. data/templates/sidebar/error.tmpl +13 -0
  78. data/templates/sidebar/footer.tmpl +22 -0
  79. data/templates/sidebar/ruwiki.css +347 -0
  80. data/templates/sidebar/save.tmpl +10 -0
  81. data/templates/simple/body.tmpl +13 -0
  82. data/templates/simple/content.tmpl +7 -0
  83. data/templates/simple/controls.tmpl +8 -0
  84. data/templates/simple/edit.tmpl +25 -0
  85. data/templates/simple/error.tmpl +10 -0
  86. data/templates/simple/footer.tmpl +10 -0
  87. data/templates/simple/ruwiki.css +192 -0
  88. data/templates/simple/save.tmpl +8 -0
  89. data/tests/harness.rb +52 -0
  90. data/tests/tc_backend_flatfile.rb +103 -0
  91. data/tests/tc_bugs.rb +74 -0
  92. data/tests/tc_exportable.rb +64 -0
  93. data/tests/tc_template.rb +145 -0
  94. data/tests/tc_tokens.rb +335 -0
  95. data/tests/testall.rb +20 -0
  96. metadata +182 -0
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+ #--
3
+ # Ruwiki
4
+ # Copyright � 2002 - 2004, Digikata and HaloStatue
5
+ # Alan Chen (alan@digikata.com)
6
+ # Austin Ziegler (ruwiki@halostatue.ca)
7
+ #
8
+ # Licensed under the same terms as Ruby.
9
+ #
10
+ # This file may be renamed to change the URI for the wiki.
11
+ #
12
+ # $Id: utils.rb,v 1.2 2004/09/27 04:48:27 austin Exp $
13
+ #++
14
+
15
+ # So that Ruwiki doesn't have to be loaded in full to use the bloody thing.
16
+ unless defined?(Ruwiki)
17
+ class Ruwiki
18
+ VERSION = "0.9.0"
19
+ end
20
+ end
21
+
22
+ module Ruwiki::Utils
23
+ RUN_PATH = Dir.pwd
24
+ end
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env ruby
2
+ #--
3
+ # Ruwiki
4
+ # Copyright � 2002 - 2004, Digikata and HaloStatue
5
+ # Alan Chen (alan@digikata.com)
6
+ # Austin Ziegler (ruwiki@halostatue.ca)
7
+ #
8
+ # Licensed under the same terms as Ruby.
9
+ #
10
+ # This file may be renamed to change the URI for the wiki.
11
+ #
12
+ # $Id: command.rb,v 1.3 2004/11/09 14:55:35 austin Exp $
13
+ #++
14
+
15
+ # Implements the command pattern. Commands are used by the command-line
16
+ class Ruwiki::Utils::CommandPattern
17
+ class AbstractCommandError < Exception; end
18
+ class UnknownCommandError < RuntimeError; end
19
+ class CommandAlreadyExists < RuntimeError; end
20
+ class MissingParameterError < ArgumentError
21
+ def initialize(argument)
22
+ @argument = argument
23
+ end
24
+
25
+ attr_reader :argument
26
+ end
27
+
28
+ class << self
29
+ def add(command)
30
+ command = command.new if command.kind_of?(Class)
31
+
32
+ @commands ||= {}
33
+ if @commands.has_key?(command.name)
34
+ raise CommandAlreadyExists
35
+ else
36
+ @commands[command.name] = command
37
+ end
38
+
39
+ if command.respond_to?(:altname)
40
+ unless @commands.has_key?(command.altname)
41
+ @commands[command.altname] = command
42
+ end
43
+ end
44
+ end
45
+
46
+ def <<(command)
47
+ add(command)
48
+ end
49
+
50
+ attr_accessor :default
51
+ def default=(command) #:nodoc:
52
+ if command.kind_of?(Ruwiki::Utils::CommandPattern)
53
+ @default = command
54
+ elsif command.kind_of?(Class)
55
+ @default = command.new
56
+ elsif @commands.has_key?(command)
57
+ @default = @commands[command]
58
+ else
59
+ raise UnknownCommandError
60
+ end
61
+ end
62
+
63
+ def command?(command)
64
+ @commands.has_key?(command)
65
+ end
66
+
67
+ def command(command)
68
+ if command?(command)
69
+ @commands[command]
70
+ else
71
+ @default
72
+ end
73
+ end
74
+
75
+ def [](cmd)
76
+ self.command(cmd)
77
+ end
78
+
79
+ def default_ioe(ioe = {})
80
+ ioe[:input] ||= $stdin
81
+ ioe[:output] ||= $stdout
82
+ ioe[:error] ||= $stderr
83
+ ioe
84
+ end
85
+ end
86
+
87
+ def [](args, opts = {}, ioe = {})
88
+ call(args, opts, ioe)
89
+ end
90
+
91
+ def name
92
+ raise AbstractCommandError
93
+ end
94
+
95
+ def call(args, opts = {}, ioe = {})
96
+ raise AbstractCommandError
97
+ end
98
+
99
+ def help
100
+ raise AbstractCommandError
101
+ end
102
+ end
@@ -0,0 +1,297 @@
1
+ #!/usr/bin/env ruby
2
+ #--
3
+ # Ruwiki
4
+ # Copyright � 2002 - 2004, Digikata and HaloStatue
5
+ # Alan Chen (alan@digikata.com)
6
+ # Austin Ziegler (ruwiki@halostatue.ca)
7
+ #
8
+ # Licensed under the same terms as Ruby.
9
+ #
10
+ # This file may be renamed to change the URI for the wiki.
11
+ #
12
+ # $Id: converter.rb,v 1.5 2004/11/26 12:18:47 austin Exp $
13
+ #++
14
+
15
+ require 'optparse'
16
+ require 'ostruct'
17
+ require 'fileutils'
18
+
19
+ module Ruwiki::Utils::Converter
20
+ class << self
21
+ TARGETS = %w(flatfiles yaml marshal)
22
+
23
+ # Create the regular expressions that are used in Ruwiki 0.6.2
24
+ OLD_HEADER_RE = /^\s*([a-z]+)\s*:\s*(.*)$/
25
+ OLD_HEADER_END_RE = /^#EHDR$/
26
+ DATA_HEADER_END_RE = /\A#EHDR\z/
27
+ NL_RE = /\n/
28
+
29
+ def with(obj)
30
+ yield obj if block_given?
31
+ end
32
+
33
+ # Only allow this to be run once. Silently fail otherwise.
34
+ def set_defaults
35
+ return unless @options.nil?
36
+ @options = OpenStruct.new
37
+
38
+ with @options do |oo|
39
+ oo.traverse_directories = true
40
+ oo.backup_old_files = true
41
+ oo.backup_extension = "~"
42
+ oo.quiet = false
43
+ oo.verbose = false
44
+ oo.extension = 'ruwiki'
45
+ oo.target_format = 'flatfiles'
46
+ end
47
+ end
48
+
49
+ def message=(lang)
50
+ if lang.kind_of?(Hash)
51
+ @message = lang
52
+ elsif "constant" == defined?(lang::Message)
53
+ @message = lang::Message
54
+ else
55
+ raise ArgumentError
56
+ end
57
+ end
58
+ def message(id)
59
+ if @message[id].nil?
60
+ []
61
+ else
62
+ @message[id]
63
+ end
64
+ end
65
+
66
+ def display_options
67
+ end
68
+
69
+ def summary
70
+ end
71
+
72
+ def run(argv, input = $stdin, output = $stdout, error = $stderr)
73
+ set_defaults
74
+
75
+ @input = input
76
+ @output = output
77
+ @error = error
78
+
79
+ language = 'en'
80
+ find_lang = argv.grep(%r{^--lang})
81
+ find_lang.each do |ee|
82
+ if ee =~ %r{^--lang=}
83
+ language = ee.sub(%r{^--lang=}, '')
84
+ else
85
+ language = argv[argv.index(ee).succ]
86
+ end
87
+ end
88
+
89
+ require "ruwiki/lang/#{language.downcase}"
90
+ self.message = Ruwiki::Lang.const_get(language.upcase)
91
+
92
+ argv.options do |opts|
93
+ opts.banner = message(:converter_usage) % File.basename($0)
94
+ opts.separator ''
95
+ opts.on('--format=FORMAT', *message(:converter_format_desc)) do |ff|
96
+ @options.target_format = ff
97
+ end
98
+ opts.on('--[no-]backup', *message(:converter_backup_desc)) do |bb|
99
+ @options.backup_old_files = bb
100
+ end
101
+ opts.on('--backup-extension=EXTENSION', *message(:converter_backupext_desc)) do |ee|
102
+ if ee.nil? or ee.empty?
103
+ @error << message(:converter_backupext_error) << "\n" if ee.nil? or ee.empty?
104
+ @error << "#{opts}\n"
105
+ return 0
106
+ end
107
+ @options.backup_extension = ee
108
+ end
109
+ opts.on('--extension=EXTENSION', *message(:converter_extension_desc)) do |ee|
110
+ if ee.nil? or ee.empty?
111
+ @error << message(:converter_extension_error) << "\n" if ee.nil? or ee.empty?
112
+ @error << "#{opts}\n"
113
+ return 0
114
+ end
115
+ @options.extension = ee
116
+ end
117
+ opts.on('--no-extension', *message(:converter_noextension_desc)) do
118
+ @options.extension = nil
119
+ end
120
+ opts.on('--lang=LANG', *message(:converter_language_desc)) do |lang|
121
+ self.message = Ruwiki::Lang.const_get(lang.upcase)
122
+ end
123
+ opts.on('--quiet', *message(:converter_quiet_desc)) do |qq|
124
+ @options.quiet = qq
125
+ @options.verbose = (not qq)
126
+ end
127
+ opts.on('--verbose', *message(:converter_verbose_desc)) do |vv|
128
+ @options.quiet = (not vv)
129
+ @options.verbose = vv
130
+ end
131
+ opts.separator ''
132
+ opts.on_tail('--help', *message(:converter_help_desc)) do
133
+ @error << "#{opts}\n"
134
+ return 0
135
+ end
136
+
137
+ opts.parse!
138
+ end
139
+
140
+ if argv.empty?
141
+ @error << message(:converter_num_arguments) << "\n#{argv.options}\n" unless @options.quiet
142
+ return 127
143
+ end
144
+
145
+ display_options if @options.verbose
146
+
147
+ @options.target_format.capitalize!
148
+ @options.target_format_class = Ruwiki::Backend.const_get(@options.target_format)
149
+
150
+ argv.each { |file| process_file(file) }
151
+
152
+ summary if not @options.quiet
153
+ end
154
+
155
+ # Process a single file.
156
+ def process_file(file)
157
+ if @options.backup_old_files
158
+ return if file =~ /#{@options.backup_extension}/
159
+ end
160
+ @out << "#{file}: " unless @options.quiet
161
+
162
+ if File.directory?(file) and @options.traverse_directories
163
+ @out << message(:converter_directory) << "\n" unless @options.quiet
164
+ Dir.chdir(file) { Dir['*'].each { |entry| process_file(entry) } }
165
+ else
166
+ begin
167
+ page, page_format = load_page(file)
168
+ @out << message(:converter_converting_from) % [ page_format, @options.target_format ] if @options.verbose
169
+ save_page(file, page)
170
+ @out << message(:converter_done) << "\n" unless @options.quiet
171
+ rescue PageLoadException
172
+ @out << message(:converter_not_ruwiki) << "\n" unless @options.quiet
173
+ rescue PageSaveException
174
+ @out << message(:cannot_nosave_modified) << "\n" % [ file ] unless @options.quiet
175
+ end
176
+ end
177
+ end
178
+
179
+ def load_page(file)
180
+ data = File.read(file)
181
+ page_format = nil
182
+
183
+ if data =~ OLD_HEADER_END_RE
184
+ page_format = 'OldFlatfiles'
185
+
186
+ page = Ruwiki::Page::NULL_PAGE.dup
187
+
188
+ unless data.empty?
189
+ rawbuf = data.split(NL_RE).map { |ee| ee.chomp }
190
+
191
+ loop do
192
+ if rawbuf[0] =~ OLD_HEADER_END_RE
193
+ rawbuf.shift
194
+ break
195
+ end
196
+
197
+ match = OLD_HEADER_RE.match(rawbuf[0])
198
+
199
+ unless match.nil?
200
+ case match.captures[0]
201
+ when 'topic'
202
+ page['properties']['topic'] = match.captures[1]
203
+ page['properties']['title'] = match.captures[1]
204
+ when 'version'
205
+ page['properties']['version'] = match.captures[1].to_i
206
+ else
207
+ nil
208
+ end
209
+ end
210
+ rawbuf.shift
211
+ end
212
+
213
+ page['page']['content'] = rawbuf.join("\n")
214
+
215
+ with page['properties'] do |pp|
216
+ pp['project'] = File.basename(File.dirname(File.expand_path(file)))
217
+ pp['editable'] = true
218
+ pp['indexable'] = true
219
+ pp['entropy'] = 0.0
220
+ end
221
+ end
222
+ end
223
+
224
+ # Try Marshal
225
+ if page_format.nil?
226
+ begin
227
+ page = ::Marshal.load(data)
228
+ page_format = 'Marshal'
229
+ rescue Exception
230
+ nil
231
+ end
232
+ end
233
+
234
+ # Try YAML
235
+ if page_format.nil?
236
+ begin
237
+ page = ::YAML.load(data)
238
+ page_format = 'YAML'
239
+ rescue Exception
240
+ nil
241
+ end
242
+ end
243
+
244
+ # Try the Flatfiles format
245
+ if page_format.nil?
246
+ begin
247
+ page = Ruwiki::Backend::Flatfiles.load(data)
248
+ page_format = 'Exportable'
249
+ rescue Exception => ex
250
+ nil
251
+ end
252
+ end
253
+
254
+ if page_format.nil? # Cannot detect page type.
255
+ @error << @message[:converter_page_format_error] << "\n"
256
+ raise PageLoadException
257
+ end
258
+ [page, page_format]
259
+ rescue PageLoadException
260
+ raise
261
+ rescue Exception => ex
262
+ @error << %Q|#{ex.message}\n#{ex.backtrace.join("\n")}\n| if @options.verbose
263
+ raise PageLoadException
264
+ end
265
+
266
+ def save_page(file, page)
267
+ if @options.backup_extension != '~'
268
+ backup = "#{file}.#{@options.backup_extension}"
269
+ else
270
+ backup = "#{file}#{@options.backup_extension}"
271
+ end
272
+
273
+ # Always backup the file -- we are transactional.
274
+ FileUtils.cp(file, backup)
275
+
276
+ if @options.target_format == 'Marshal'
277
+ method = :print
278
+ else
279
+ method = :puts
280
+ end
281
+ File.open(file, 'wb') { |ff| ff.__send__(method, @options.target_format_class.dump(page)) }
282
+ rescue Exception => ex
283
+ FileUtils.mv(backup, file) if File.exists?(backup)
284
+ @error << %Q|#{ex.message}\n#{ex.backtrace.join("\n")}\n| if @options.verbose
285
+ raise PageSaveException
286
+ ensure
287
+ # If we aren't *supposed* to back up the file, then get rid of the
288
+ # backup.
289
+ if File.exists?(backup) and (not @options.backup_old_files)
290
+ FileUtils.rm(backup)
291
+ end
292
+ end
293
+
294
+ class PageLoadException < RuntimeError; end
295
+ class PageSaveException < RuntimeError; end
296
+ end
297
+ end
@@ -0,0 +1,639 @@
1
+ #!/usr/bin/env ruby
2
+ #--
3
+ # Ruwiki
4
+ # Copyright � 2002 - 2004, Digikata and HaloStatue
5
+ # Alan Chen (alan@digikata.com)
6
+ # Austin Ziegler (ruwiki@halostatue.ca)
7
+ #
8
+ # Licensed under the same terms as Ruby.
9
+ #
10
+ # This file may be renamed to change the URI for the wiki.
11
+ #
12
+ # $Id: manager.rb,v 1.10 2004/11/28 02:26:57 austin Exp $
13
+ #++
14
+
15
+ require 'optparse'
16
+ require 'ostruct'
17
+ require 'fileutils'
18
+ require 'stringio'
19
+ require 'zlib'
20
+ require 'ruwiki/exportable'
21
+ require 'ruwiki/utils/command'
22
+ require 'ruwiki/config'
23
+
24
+ begin
25
+ if defined?(Gem::Cache)
26
+ require_gem 'archive-tar-minitar', '~> 0.5.1'
27
+ else
28
+ require 'archive/tar/minitar'
29
+ end
30
+ rescue LoadError => ex
31
+ $stderr.puts ex.message
32
+ raise
33
+ end
34
+
35
+ module Ruwiki::Utils::Manager
36
+ DEFAULT_PACKAGE_NAME = 'ruwiki.pkg'
37
+
38
+ def self.message=(lang)
39
+ if lang.kind_of?(Hash)
40
+ @message = lang
41
+ elsif "constant" == defined?(lang::Message)
42
+ @message = lang::Message
43
+ else
44
+ raise ArgumentError
45
+ end
46
+ end
47
+ def self.message(id)
48
+ @message[id]
49
+ end
50
+
51
+ class ManagerError < RuntimeError; end
52
+
53
+ EXECUTABLES = %w(ruwiki.cgi ruwiki_servlet ruwiki_servlet.bat \
54
+ ruwiki_servlet.cmd ruwiki_service.rb)
55
+
56
+ class ManagerHelp < Ruwiki::Utils::CommandPattern
57
+ def name
58
+ "help"
59
+ end
60
+
61
+ def call(args, opts = {}, ioe = {})
62
+ ioe = Ruwiki::Utils::CommandPattern.default_ioe(ioe)
63
+ help_on = args.shift
64
+ output = ""
65
+
66
+ if Ruwiki::Utils::CommandPattern.command?(help_on)
67
+ ioe[:output] << Ruwiki::Utils::CommandPattern[help_on].help
68
+ elsif help_on == "commands"
69
+ ioe[:output] << Ruwiki::Utils::Manager.message(:manager_help_commands)
70
+ else
71
+ ioe[:output] << Ruwiki::Utils::Manager.message(:manager_unknown_command) % [ help_on ] << "\n" % [ help_on ] unless help_on.nil? or help_on.empty?
72
+ ioe[:output] << self.help
73
+ end
74
+
75
+ 0
76
+ end
77
+
78
+ def help
79
+ Ruwiki::Utils::Manager.message(:manager_help_help)
80
+ end
81
+ end
82
+
83
+ class ManagerInstall < Ruwiki::Utils::CommandPattern
84
+ def name
85
+ "install"
86
+ end
87
+
88
+ def call(args, opts = {}, ioe = {})
89
+ argv = []
90
+
91
+ replace = false
92
+ dest = "."
93
+ name = nil
94
+
95
+ while (arg = args.shift)
96
+ case arg
97
+ when '--to'
98
+ dir = args.shift
99
+ raise Ruwiki::Utils::CommandPattern::MissingParameterError.new(arg) if dir.nil?
100
+ if File.exist?(dir)
101
+ if not File.directory?(dir)
102
+ raise ArgumentError, Ruwiki::Utils::Manager.message(:manager_dest_not_directory)
103
+ end
104
+ else
105
+ FileUtils.mkdir_p(dir)
106
+ end
107
+ dest = dir
108
+ when /;/o
109
+ argv.push(*(arg.split(/;/o)))
110
+ when /,/o
111
+ argv.push(*(arg.split(/,/o)))
112
+ else
113
+ argv << arg
114
+ end
115
+ end
116
+
117
+ options = { 'data' => true }
118
+
119
+ while (arg = argv.shift)
120
+ case arg
121
+ when /^(?:-|no)(.*$)/
122
+ options.delete($1)
123
+ else
124
+ options[arg] = true
125
+ end
126
+ end
127
+
128
+ Ruwiki::Utils::Manager.install(dest, options)
129
+
130
+ 0
131
+ end
132
+
133
+ def help
134
+ Ruwiki::Utils::Manager.message(:manager_install_help)
135
+ end
136
+ end
137
+
138
+ class ManagerPackage < Ruwiki::Utils::CommandPattern
139
+ def name
140
+ "package"
141
+ end
142
+
143
+ def call(args, opts = {}, ioe = {})
144
+ ioe = Ruwiki::Utils::CommandPattern.default_ioe(ioe)
145
+ argv = []
146
+ replace = false
147
+ dest = "."
148
+ name = nil
149
+
150
+ while (arg = args.shift)
151
+ case arg
152
+ when '--replace'
153
+ replace = true
154
+ when '-o', '--output'
155
+ name = args.shift
156
+ raise Ruwiki::Utils::CommandPattern::MissingParameterError.new(arg) if name.nil?
157
+ dest = File.dirname(name)
158
+ name = File.basename(name)
159
+ else
160
+ argv << arg
161
+ end
162
+ end
163
+
164
+ if argv.size > 1
165
+ ioe[:output] << Ruwiki::Utils::Manager.message(:manager_service_hi_argcount) % [ args.join(" ") ] << "\n"
166
+ ioe[:output] << self.help
167
+ return 1
168
+ end
169
+ source = argv.shift || "."
170
+
171
+ Ruwiki::Utils::Manager.package(source, dest, name, replace)
172
+ 0
173
+ end
174
+
175
+ def help
176
+ Ruwiki::Utils::Manager.message(:manager_package_help) % [ "./#{Ruwiki::Utils::Manager::DEFAULT_PACKAGE_NAME}",
177
+ Ruwiki::Config::CONFIG_NAME ]
178
+ end
179
+ end
180
+
181
+ class ManagerUnpackage < Ruwiki::Utils::CommandPattern
182
+ def name
183
+ "unpackage"
184
+ end
185
+
186
+ def call(args, opts = {}, ioe = {})
187
+ ioe = Ruwiki::Utils::CommandPattern.default_ioe(ioe)
188
+ argv = []
189
+ dir = "."
190
+
191
+ while (arg = args.shift)
192
+ case arg
193
+ when '-o', '--output'
194
+ dir = args.shift
195
+ raise Ruwiki::Utils::CommandPatter::MissingParameterError.new(arg) if dir.nil? or not File.directory?(dir)
196
+ else
197
+ argv << arg
198
+ end
199
+ end
200
+
201
+ if argv.size > 1
202
+ ioe[:output] << Ruwiki::Utils::Manager.message(:manager_service_hi_argcount) % [ args.join(" ") ] << "\n"
203
+ ioe[:output] << self.help
204
+ return 1
205
+ end
206
+ source = argv.shift || Ruwiki::Utils::Manager::DEFAULT_PACKAGE_NAME
207
+
208
+ Ruwiki::Utils::Manager.unpackage(source, dir)
209
+
210
+ 0
211
+ end
212
+
213
+ def help
214
+ Ruwiki::Utils::Manager.message(:manager_unpackage_help) % [ "./#{Ruwiki::Utils::Manager::DEFAULT_PACKAGE_NAME}" ]
215
+ end
216
+ end
217
+
218
+ if RUBY_PLATFORM =~ /win32/
219
+ class ManagerService < Ruwiki::Utils::CommandPattern
220
+ def name
221
+ "service"
222
+ end
223
+
224
+ def call(args, opts = {}, ioe = {})
225
+ ioe = Ruwiki::Utils::CommandPattern.default_ioe(ioe)
226
+
227
+ if args.size < 2
228
+ ioe[:output] << Ruwiki::Utils::Manager.message(:manager_service_lo_argcount) % [ args.join(" ") ] << "\n"
229
+ ioe[:output] << self.help
230
+ return 0
231
+ end
232
+
233
+ command = args.shift
234
+ service = args.shift
235
+
236
+ options ||= {}
237
+ options[:service_name] = service
238
+ options[:service_home] = File.expand_path(".")
239
+
240
+ argv = []
241
+ while (arg = args.shift)
242
+ case arg
243
+ when "--rubybin"
244
+ options[:ruby_bin] = args.shift
245
+ raise Ruwiki::Utils::CommandPattern::MissingParameterError.new(arg) if options[:ruby_bin].nil?
246
+ when "--exec"
247
+ options[:service_bin] = args.shift
248
+ raise Ruwiki::Utils::CommandPattern::MissingParameterError.new(arg) if options[:service_bin].nil?
249
+ when "--home"
250
+ options[:service_home] = args.shift
251
+ raise Ruwiki::Utils::CommandPattern::MissingParameterError.new(arg) if options[:service_home].nil?
252
+ else
253
+ argv << arg
254
+ end
255
+ end
256
+
257
+ options[:service_desc] = args.join(" ") if args.size > 0
258
+
259
+ case command
260
+ when "install"
261
+ options[:service_install] = true
262
+ when "start"
263
+ options[:service_start] = true
264
+ when "stop"
265
+ options[:service_stop] = true
266
+ when "delete"
267
+ options[:service_delete] = true
268
+ else
269
+ raise ArgumentError, Ruwiki::Utils::Manager.message(:manager_unknown_command) % [ command ]
270
+ end
271
+
272
+ Ruwiki::Utils::Manager.manage_windows_service(options, ioe)
273
+
274
+ 0
275
+ end
276
+
277
+ def help
278
+ Ruwiki::Utils::Manager.message(:manager_service_help)
279
+ end
280
+ end
281
+ Ruwiki::Utils::CommandPattern << ManagerService
282
+ end
283
+
284
+ Ruwiki::Utils::CommandPattern << ManagerHelp
285
+ Ruwiki::Utils::CommandPattern << ManagerInstall
286
+ Ruwiki::Utils::CommandPattern << ManagerPackage
287
+ Ruwiki::Utils::CommandPattern << ManagerUnpackage
288
+ Ruwiki::Utils::CommandPattern.default = Ruwiki::Utils::CommandPattern["help"]
289
+
290
+ class << self
291
+ attr_accessor :shared
292
+ attr_reader :ruwiki_servlet
293
+ attr_reader :ruwiki_servlet_bat
294
+ attr_reader :ruwiki_servlet_cmd
295
+ attr_reader :ruwiki_service
296
+ attr_reader :ruwiki_cgi
297
+ attr_reader :ruwiki_pkg
298
+ def shared=(shared)
299
+ @shared = shared
300
+ @ruwiki_servlet = File.join(@shared, "bin", "ruwiki_servlet")
301
+ @ruwiki_servlet_bat = File.join(@shared, "bin", "ruwiki_servlet.bat")
302
+ @ruwiki_servlet_cmd = File.join(@shared, "bin", "ruwiki_servlet.cmd")
303
+ @ruwiki_service = File.join(@shared, "bin", "ruwiki_service.rb")
304
+ @ruwiki_cgi = File.join(@shared, "bin", "ruwiki.cgi")
305
+ @ruwiki_pkg = File.join(@shared, Ruwiki::Utils::Manager::DEFAULT_PACKAGE_NAME)
306
+ end
307
+
308
+ def with(obj)
309
+ yield obj if block_given?
310
+ end
311
+
312
+ def tar_files(list, name)
313
+ ff = StringIO.new
314
+ gz = Zlib::GzipWriter.new(ff)
315
+ to = Archive::Tar::Minitar::Output.new(gz)
316
+ list.each { |item| Archive::Tar::Minitar.pack_file(item, to) }
317
+ data = ff.string
318
+ group = {
319
+ :name => name,
320
+ :data => data,
321
+ :mode => 0644,
322
+ }
323
+ return group
324
+ rescue Exception => ex
325
+ puts ex.message, ex.backtrace.join("\n")
326
+ ensure
327
+ to.close
328
+ group[:size] = group[:data].size
329
+ end
330
+
331
+ def package(source, dest, name = nil, replace = false)
332
+ # If the package name is nil, use the default name. If replace is
333
+ # false, then append a number on the end if the file already exists.
334
+ # Increment the number until we have a unique filename.
335
+ if name.nil?
336
+ pkg = File.join(dest, DEFAULT_PACKAGE_NAME)
337
+ if File.exists?(pkg) and (not replace)
338
+ pbn = "#{File.basename(DEFAULT_PACKAGE_NAME, '.pkg')}-%02d.pkg"
339
+ ii = 1
340
+ while File.exists?(pkg)
341
+ pkg = File.join(dest, pbn % ii)
342
+ ii += 1
343
+ end
344
+ end
345
+ else
346
+ pkg = File.join(dest, name)
347
+ if File.exists?(pkg) and (not replace)
348
+ raise ManagerError, Ruwiki::Utils::Manager.message(:manager_package_exists)
349
+ end
350
+ end
351
+
352
+ files = []
353
+
354
+ if File.directory?(source)
355
+ Dir.chdir(source) do
356
+ if File.exists?(Ruwiki::Config::CONFIG_NAME)
357
+ cs = File.stat(Ruwiki::Config::CONFIG_NAME)
358
+ files << {
359
+ :name => Ruwiki::Config::CONFIG_NAME,
360
+ :data => File.read(Ruwiki::Config::CONFIG_NAME),
361
+ :mtime => cs.mtime,
362
+ :mode => 0644,
363
+ :size => cs.size
364
+ }
365
+ end
366
+
367
+ EXECUTABLES.each do |ff|
368
+ if File.exists?(ff)
369
+ cs = File.stat(ff)
370
+ files << {
371
+ :name => ff,
372
+ :data => File.read(ff),
373
+ :mtime => cs.mtime,
374
+ :mode => 0755,
375
+ :size => cs.size
376
+ }
377
+ end
378
+ end
379
+
380
+ f_data = Dir["data/**/**"].select { |dd| dd !~ /CVS\// }
381
+ f_data.unshift("data")
382
+ f_data.map! do |dd|
383
+ res = { :name => dd, :mode => 0644 }
384
+ if File.directory?(dd)
385
+ res[:mode] = 0755
386
+ res[:dir] = true
387
+ end
388
+ res
389
+ end
390
+
391
+ f_tmpl = Dir["templates/**/**"].select { |tt| tt !~ /CVS\// }
392
+ f_tmpl.unshift("templates")
393
+ f_tmpl.map! do |tt|
394
+ res = { :name => tt, :mode => 0644 }
395
+ if File.directory?(tt)
396
+ res[:mode] = 0755
397
+ res[:dir] = true
398
+ end
399
+ res
400
+ end
401
+
402
+ files << tar_files(f_data, "data.pkg")
403
+ files << tar_files(f_tmpl, "tmpl.pkg")
404
+ end
405
+ else
406
+ stat = File.stat(source)
407
+ files << {
408
+ :name => File.basename(source),
409
+ :data => File.read(source),
410
+ :mtime => stat.mtime,
411
+ :mode => 0644,
412
+ :size => stat.size
413
+ }
414
+
415
+ EXECUTABLES.each do |ff|
416
+ ff = File.join(File.dirname(source), ff)
417
+ if File.exists?(ff)
418
+ cs = File.stat(ff)
419
+ files << {
420
+ :name => ff,
421
+ :data => File.read(ff),
422
+ :mtime => cs.mtime,
423
+ :mode => 0755,
424
+ :size => cs.size
425
+ }
426
+ end
427
+ end
428
+
429
+ cc = Ruwiki::Exportable.load(files[0][:data])
430
+ tp = cc['ruwiki-config']['template-path']
431
+ tp = "./templates" if tp.nil? or tp.empty?
432
+ so = cc['ruwiki-config']['storage-options']
433
+
434
+ if so.nil? or so.empty?
435
+ dp = "./data"
436
+ else
437
+ so = Ruwiki::Exportable.load(so)
438
+ key = 'flatfiles'
439
+ dp = so[key]['data-path']
440
+ end
441
+
442
+ dp = "./data" if dp.nil? or dp.empty?
443
+ bndp = File.basename(dp)
444
+ bntp = File.basename(tp)
445
+
446
+ so[key]['data-path'] = bndp
447
+ cc['ruwiki-config']['storage-options'] = Ruwiki::Exportable.dump(so)
448
+ cc['ruwiki-config']['template-path'] = bntp
449
+ files[0][:data] = Ruwiki::Exportable.dump(cc)
450
+ files[0][:size] = files[0][:data].size
451
+
452
+ Dir.chdir(File.dirname(dp)) do
453
+ f_data = Dir["#{bndp}/**/**"].select { |dd| dd !~ /CVS\// }
454
+ f_data.map! { |dd| { :name => dd, :mode => 0644 } }
455
+ files << tar_files(f_data, "data.pkg")
456
+ end
457
+
458
+ Dir.chdir(File.dirname(tp)) do
459
+ f_tmpl = Dir["#{bntp}/**/**"].select { |tt| tt !~ /CVS\// }
460
+ f_tmpl.map! { |tt| { :name => tt, :mode => 0644 } }
461
+ files << tar_files(f_tmpl, "tmpl.pkg")
462
+ end
463
+ end
464
+
465
+ ff = File.open(pkg, "wb")
466
+ gz = Zlib::GzipWriter.new(ff)
467
+ tw = Archive::Tar::Minitar::Writer.new(gz)
468
+
469
+ files.each do |entry|
470
+ tw.add_file_simple(entry[:name], entry) { |os| os.write(entry[:data]) }
471
+ end
472
+
473
+ nil
474
+ rescue Exception => ex
475
+ puts ex, ex.backtrace.join("\n")
476
+ ensure
477
+ tw.close if tw
478
+ gz.close if gz
479
+ end
480
+
481
+ def unpackage(source, dest)
482
+ ff = File.open(source, "rb")
483
+ gz = Zlib::GzipReader.new(ff)
484
+ Archive::Tar::Minitar::Input.open(gz) do |it|
485
+ it.each do |entry|
486
+ case entry.full_name
487
+ when "data.pkg", "tmpl.pkg"
488
+ pkg = StringIO.new(entry.read)
489
+ pkgz = Zlib::GzipReader.new(pkg)
490
+ Archive::Tar::Minitar::Input.open(pkgz) do |inner|
491
+ inner.each { |item| inner.extract_entry(dest, item) }
492
+ end
493
+ else
494
+ it.extract_entry(dest, entry)
495
+ end
496
+ end
497
+ end
498
+
499
+ nil
500
+ end
501
+
502
+ def install(dest, options = {})
503
+ if options['servlet']
504
+ FileUtils.install(Ruwiki::Utils::Manager.ruwiki_servlet, dest, :mode => 0755)
505
+ if RUBY_PLATFORM =~ /win32/
506
+ if File.exists?(Ruwiki::Utils::Manager.ruwiki_servlet_bat)
507
+ FileUtils.install(Ruwiki::Utils::Manager.ruwiki_servlet_bat, dest, :mode => 0755)
508
+ end
509
+ if File.exists?(Ruwiki::Utils::Manager.ruwiki_servlet_cmd)
510
+ FileUtils.install(Ruwiki::Utils::Manager.ruwiki_servlet_cmd, dest, :mode => 0755)
511
+ end
512
+ end
513
+ end
514
+
515
+ if RUBY_PLATFORM =~ /win32/ and options['service']
516
+ FileUtils.install(Ruwiki::Utils::Manager.ruwiki_service, dest, :mode => 0755)
517
+ end
518
+
519
+ if options['cgi']
520
+ FileUtils.install(Ruwiki::Utils::Manager.ruwiki_cgi, dest, :mode => 0755)
521
+ end
522
+
523
+ if options['data']
524
+ unpackage(Ruwiki::Utils::Manager.ruwiki_pkg, dest)
525
+ end
526
+ end
527
+
528
+ if RUBY_PLATFORM =~ /win32/
529
+ begin
530
+ require 'win32/service'
531
+ require 'rbconfig'
532
+ HasWin32Service = true
533
+ rescue LoadError
534
+ HasWin32Service = false
535
+ end
536
+
537
+ # The work here is based on Daniel Berger's Instiki Service Tutorial.
538
+ # http://rubyforge.org/docman/view.php/85/107/instiki_service_tutorial.txt
539
+ def manage_windows_service(options, ioe)
540
+ raise Ruwiki::Utils::Manager.message(:manager_service_broken) unless HasWin32Service
541
+
542
+ service_name = options[:service_name] || 'RuwikiSvc'
543
+
544
+ if options[:service_install]
545
+ service_home = options[:service_home]
546
+
547
+ program = options[:service_bin]
548
+ if program.nil? or program.empty?
549
+ program = File.join(service_home, "ruwiki_service.rb")
550
+ elsif program !~ %r{[/\\]}
551
+ program = File.join(service_home, program)
552
+ end
553
+ program = %<"#{program}">
554
+
555
+ ruby = options[:ruby_bin] || %<"#{File.join(Config::CONFIG['bindir'], 'ruby.exe')}">
556
+
557
+ service_desc = options[:service_desc] || 'Ruwiki'
558
+
559
+ binpath = "#{ruby} #{program}".tr('/', '\\')
560
+
561
+ service = Win32::Service.new
562
+ service.create_service do |svc|
563
+ svc.service_name = service_name
564
+ svc.display_name = service_desc
565
+ svc.binary_path_name = binpath
566
+ svc.dependencies = [] # Required because of a bug in Win32::Service
567
+ end
568
+ service.close
569
+ ioe[:output] << Manager.manager(:manager_service_installed) % [ service_name ] << "\n"
570
+ end
571
+
572
+ if options[:service_start]
573
+ Win32::Service.start(service_name)
574
+ started = false
575
+ while (not started)
576
+ status = Win32::Service.status(service_name)
577
+ started = (status.current_state == "running")
578
+ break if started
579
+ ioe[:output] << Ruwiki::Utils::Manager.message(:manager_one_moment) % [ status.current_state ] << "\n"
580
+ sleep 1
581
+ end
582
+ ioe[:output] << Ruwiki::Utils::Manager.message(:manager_service_started) % [ service_name ] << "\n"
583
+ end
584
+
585
+ if options[:service_stop]
586
+ Win32::Service.stop(service_name)
587
+ stopped = false
588
+ while (not stopped)
589
+ status = Win32::Service.status(service_name)
590
+ stopped = (status.current_state == "stopped")
591
+ break if stopped
592
+ ioe[:output] << Ruwiki::Utils::Manager.message(:manager_one_moment) % [ status.current_state ] << "\n"
593
+ sleep 1
594
+ end
595
+ ioe[:output] << Ruwiki::Utils::Manager.message(:manager_service_stopped) % [ service_name ] << "\n"
596
+ end
597
+
598
+ if options[:service_delete]
599
+ Win32::Service.stop(service_name) rescue nil
600
+ Win32::Service.delete(service_name)
601
+ ioe[:output] << Ruwiki::Utils::Manager.message(:manager_service_deleted) % [ service_name ] << "\n"
602
+ end
603
+ end
604
+ end
605
+
606
+ def run(argv, input = $stdin, output = $stdout, error = $stderr)
607
+ ioe = {
608
+ :input => input,
609
+ :output => output,
610
+ :error => error
611
+ }
612
+
613
+ language = 'en'
614
+ find_lang = argv.grep(%r{^--lang})
615
+ find_lang.each do |ee|
616
+ eepos = argv.index(ee)
617
+ if ee =~ %r{^--lang=}
618
+ language = ee.sub(%r{^--lang=}, '')
619
+ else
620
+ language = argv[eepos.succ]
621
+ argv.delete_at(eepos.succ)
622
+ end
623
+ argv.delete_at(eepos)
624
+ end
625
+
626
+ require "ruwiki/lang/#{language.downcase}"
627
+ Ruwiki::Utils::Manager.message = Ruwiki::Lang.const_get(language.upcase)
628
+
629
+ command = Ruwiki::Utils::CommandPattern[(argv.shift or "").downcase]
630
+ return command[argv, {}, ioe]
631
+ rescue Ruwiki::Utils::CommandPattern::MissingParameterError => ee
632
+ ioe[:error] << Ruwiki::Utils::Manager.message(:manager_missing_parameter) % [ ee.argument ] << "\n"
633
+ return 1
634
+ rescue ArgumentError, ManagerError => ee
635
+ ioe[:error] << ee.message << "\n"
636
+ return 1
637
+ end
638
+ end
639
+ end