rtfmd 0.10301.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/HISTORY.md +93 -0
  2. data/LICENSE +21 -0
  3. data/README.md +393 -0
  4. data/bin/rtfm +0 -0
  5. data/bin/rtfmd +4 -0
  6. data/config/rtfmd.ru +33 -0
  7. data/docs/sanitization.md +32 -0
  8. data/lib/gollum.rb +39 -0
  9. data/lib/gollum/blob_entry.rb +78 -0
  10. data/lib/gollum/committer.rb +217 -0
  11. data/lib/gollum/file.rb +64 -0
  12. data/lib/gollum/frontend/app.rb +96 -0
  13. data/lib/gollum/frontend/indexapp.rb +17 -0
  14. data/lib/gollum/frontend/public/css/gollum.css +660 -0
  15. data/lib/gollum/frontend/public/css/ie7.css +69 -0
  16. data/lib/gollum/frontend/public/css/ronn.css +40 -0
  17. data/lib/gollum/frontend/public/css/template.css +381 -0
  18. data/lib/gollum/frontend/public/images/icon-sprite.png +0 -0
  19. data/lib/gollum/frontend/public/javascript/gollum.js +137 -0
  20. data/lib/gollum/frontend/public/javascript/gollum.placeholder.js +54 -0
  21. data/lib/gollum/frontend/public/javascript/jquery.color.js +123 -0
  22. data/lib/gollum/frontend/public/javascript/jquery.js +7179 -0
  23. data/lib/gollum/frontend/templates/error.mustache +8 -0
  24. data/lib/gollum/frontend/templates/index.mustache +25 -0
  25. data/lib/gollum/frontend/templates/layout.mustache +28 -0
  26. data/lib/gollum/frontend/templates/page.mustache +34 -0
  27. data/lib/gollum/frontend/templates/pages.mustache +31 -0
  28. data/lib/gollum/frontend/views/error.rb +7 -0
  29. data/lib/gollum/frontend/views/index.rb +21 -0
  30. data/lib/gollum/frontend/views/layout.rb +28 -0
  31. data/lib/gollum/frontend/views/page.rb +53 -0
  32. data/lib/gollum/frontend/views/pages.rb +19 -0
  33. data/lib/gollum/git_access.rb +248 -0
  34. data/lib/gollum/markup.rb +389 -0
  35. data/lib/gollum/page.rb +374 -0
  36. data/lib/gollum/pagination.rb +61 -0
  37. data/lib/gollum/sanitization.rb +161 -0
  38. data/lib/gollum/wiki.rb +378 -0
  39. data/rtfmd.gemspec +47 -0
  40. metadata +291 -0
@@ -0,0 +1,61 @@
1
+ module Gollum
2
+ module Pagination
3
+ def self.included(klass)
4
+ klass.extend ClassMethods
5
+ class << klass
6
+ # Default Integer max count of items to return in git commands.
7
+ attr_accessor :per_page
8
+ end
9
+ klass.per_page = 30
10
+ end
11
+
12
+ module ClassMethods
13
+ # Turns a page number into an offset number for the git skip option.
14
+ #
15
+ # page - Integer page number.
16
+ #
17
+ # Returns an Integer.
18
+ def page_to_skip(page)
19
+ ([1, page.to_i].max - 1) * per_page
20
+ end
21
+
22
+ # Fills in git-specific options for the log command using simple
23
+ # pagination options.
24
+ #
25
+ # options - Hash of options:
26
+ # page - Optional Integer page number (default: 1)
27
+ # per_page - Optional Integer max count of items to return.
28
+ # Defaults to #per_class class method.
29
+ #
30
+ # Returns Hash with :max_count and :skip keys.
31
+ def log_pagination_options(options = {})
32
+ skip = page_to_skip(options.delete(:page))
33
+ options[:max_count] = [options.delete(:per_page).to_i, per_page].max
34
+ options[:skip] = skip if skip > 0
35
+ options
36
+ end
37
+ end
38
+
39
+ # Turns a page number into an offset number for the git skip option.
40
+ #
41
+ # page - Integer page number.
42
+ #
43
+ # Returns an Integer.
44
+ def page_to_skip(page)
45
+ self.class.page_to_skip(page)
46
+ end
47
+
48
+ # Fills in git-specific options for the log command using simple
49
+ # pagination options.
50
+ #
51
+ # options - Hash of options:
52
+ # page - Optional Integer page number (default: 1)
53
+ # per_page - Optional Integer max count of items to return.
54
+ # Defaults to #per_class class method.
55
+ #
56
+ # Returns Hash with :max_count and :skip keys.
57
+ def log_pagination_options(options = {})
58
+ self.class.log_pagination_options(options)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,161 @@
1
+ module Gollum
2
+ # Encapsulate sanitization options.
3
+ #
4
+ # This class does not yet support all options of Sanitize library.
5
+ # See http://github.com/rgrove/sanitize/.
6
+ class Sanitization
7
+ # Default whitelisted elements.
8
+ ELEMENTS = [
9
+ 'a', 'abbr', 'acronym', 'address', 'area', 'b', 'big',
10
+ 'blockquote', 'br', 'button', 'caption', 'center', 'cite',
11
+ 'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'dir',
12
+ 'div', 'dl', 'dt', 'em', 'fieldset', 'font', 'form', 'h1',
13
+ 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'input',
14
+ 'ins', 'kbd', 'label', 'legend', 'li', 'map', 'menu',
15
+ 'ol', 'optgroup', 'option', 'p', 'pre', 'q', 's', 'samp',
16
+ 'select', 'small', 'span', 'strike', 'strong', 'sub',
17
+ 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th',
18
+ 'thead', 'tr', 'tt', 'u', 'ul', 'var'
19
+ ].freeze
20
+
21
+ # Default whitelisted attributes.
22
+ ATTRIBUTES = {
23
+ 'a' => ['href'],
24
+ 'img' => ['src'],
25
+ :all => ['abbr', 'accept', 'accept-charset',
26
+ 'accesskey', 'action', 'align', 'alt', 'axis',
27
+ 'border', 'cellpadding', 'cellspacing', 'char',
28
+ 'charoff', 'class', 'charset', 'checked', 'cite',
29
+ 'clear', 'cols', 'colspan', 'color',
30
+ 'compact', 'coords', 'datetime', 'dir',
31
+ 'disabled', 'enctype', 'for', 'frame',
32
+ 'headers', 'height', 'hreflang',
33
+ 'hspace', 'ismap', 'label', 'lang',
34
+ 'longdesc', 'maxlength', 'media', 'method',
35
+ 'multiple', 'name', 'nohref', 'noshade',
36
+ 'nowrap', 'prompt', 'readonly', 'rel', 'rev',
37
+ 'rows', 'rowspan', 'rules', 'scope',
38
+ 'selected', 'shape', 'size', 'span',
39
+ 'start', 'summary', 'tabindex', 'target',
40
+ 'title', 'type', 'usemap', 'valign', 'value',
41
+ 'vspace', 'width']
42
+ }.freeze
43
+
44
+ # Default whitelisted protocols for URLs.
45
+ PROTOCOLS = {
46
+ 'a' => {'href' => ['http', 'https', 'mailto', :relative]},
47
+ 'img' => {'src' => ['http', 'https', :relative]}
48
+ }.freeze
49
+
50
+ ADD_ATTRIBUTES = lambda do |env, node|
51
+ if add = env[:config][:add_attributes][node.name]
52
+ add.each do |key, value|
53
+ node[key] = value
54
+ end
55
+ end
56
+ end
57
+
58
+ # Default transformers to force @id attributes with 'wiki-' prefix
59
+ TRANSFORMERS = [
60
+ lambda do |env|
61
+ node = env[:node]
62
+ return if env[:is_whitelisted] || !node.element?
63
+ prefix = env[:config][:id_prefix]
64
+ found_attrs = %w(id name).select do |key|
65
+ if value = node[key]
66
+ node[key] = value.gsub(/\A(#{prefix})?/, prefix)
67
+ end
68
+ end
69
+ if found_attrs.size > 0
70
+ ADD_ATTRIBUTES.call(env, node)
71
+ {}
72
+ end
73
+ end,
74
+ lambda do |env|
75
+ node = env[:node]
76
+ return unless value = node['href']
77
+ prefix = env[:config][:id_prefix]
78
+ node['href'] = value.gsub(/\A\#(#{prefix})?/, '#'+prefix)
79
+ ADD_ATTRIBUTES.call(env, node)
80
+ {}
81
+ end
82
+ ].freeze
83
+
84
+ # Gets an Array of whitelisted HTML elements. Default: ELEMENTS.
85
+ attr_reader :elements
86
+
87
+ # Gets a Hash describing which attributes are allowed in which HTML
88
+ # elements. Default: ATTRIBUTES.
89
+ attr_reader :attributes
90
+
91
+ # Gets a Hash describing which URI protocols are allowed in HTML
92
+ # attributes. Default: PROTOCOLS
93
+ attr_reader :protocols
94
+
95
+ # Gets a Hash describing which URI protocols are allowed in HTML
96
+ # attributes. Default: TRANSFORMERS
97
+ attr_reader :transformers
98
+
99
+ # Gets or sets a String prefix which is added to ID attributes.
100
+ # Default: 'wiki-'
101
+ attr_accessor :id_prefix
102
+
103
+ # Gets a Hash describing HTML attributes that Sanitize should add.
104
+ # Default: {}
105
+ attr_reader :add_attributes
106
+
107
+ # Sets a boolean determining whether Sanitize allows HTML comments in the
108
+ # output. Default: false.
109
+ attr_writer :allow_comments
110
+
111
+ def initialize
112
+ @elements = ELEMENTS
113
+ @attributes = ATTRIBUTES
114
+ @protocols = PROTOCOLS
115
+ @transformers = TRANSFORMERS
116
+ @add_attributes = {}
117
+ @allow_comments = false
118
+ @id_prefix = 'wiki-'
119
+ yield self if block_given?
120
+ end
121
+
122
+ # Determines if Sanitize should allow HTML comments.
123
+ #
124
+ # Returns True if comments are allowed, or False.
125
+ def allow_comments?
126
+ !!@allow_comments
127
+ end
128
+
129
+ # Modifies the current Sanitization instance to sanitize older revisions
130
+ # of pages.
131
+ #
132
+ # Returns a Sanitization instance.
133
+ def history_sanitization
134
+ self.class.new do |sanitize|
135
+ sanitize.add_attributes['a'] = {'rel' => 'nofollow'}
136
+ end
137
+ end
138
+
139
+ # Builds a Hash of options suitable for Sanitize.clean.
140
+ #
141
+ # Returns a Hash.
142
+ def to_hash
143
+ { :elements => elements,
144
+ :attributes => attributes,
145
+ :protocols => protocols,
146
+ :add_attributes => add_attributes,
147
+ :allow_comments => allow_comments?,
148
+ :transformers => transformers,
149
+ :id_prefix => id_prefix
150
+ }
151
+ end
152
+
153
+ # Builds a Sanitize instance from the current options.
154
+ #
155
+ # Returns a Sanitize instance.
156
+ def to_sanitize
157
+ Sanitize.new(to_hash)
158
+ end
159
+ end
160
+ end
161
+
@@ -0,0 +1,378 @@
1
+ module Gollum
2
+ class Wiki
3
+ include Pagination
4
+
5
+ class << self
6
+ # Sets the page class used by all instances of this Wiki.
7
+ attr_writer :page_class
8
+
9
+ # Sets the file class used by all instances of this Wiki.
10
+ attr_writer :file_class
11
+
12
+ # Sets the markup class used by all instances of this Wiki.
13
+ attr_writer :markup_classes
14
+
15
+ # Sets the default ref for the wiki.
16
+ attr_accessor :default_ref
17
+
18
+ # Sets the default name for commits.
19
+ attr_accessor :default_committer_name
20
+
21
+ # Sets the default email for commits.
22
+ attr_accessor :default_committer_email
23
+
24
+ # Sets sanitization options. Set to false to deactivate
25
+ # sanitization altogether.
26
+ attr_writer :sanitization
27
+
28
+ # Sets sanitization options. Set to false to deactivate
29
+ # sanitization altogether.
30
+ attr_writer :history_sanitization
31
+
32
+ # Gets the page class used by all instances of this Wiki.
33
+ # Default: Gollum::Page.
34
+ def page_class
35
+ @page_class ||
36
+ if superclass.respond_to?(:page_class)
37
+ superclass.page_class
38
+ else
39
+ ::Gollum::Page
40
+ end
41
+ end
42
+
43
+ # Gets the file class used by all instances of this Wiki.
44
+ # Default: Gollum::File.
45
+ def file_class
46
+ @file_class ||
47
+ if superclass.respond_to?(:file_class)
48
+ superclass.file_class
49
+ else
50
+ ::Gollum::File
51
+ end
52
+ end
53
+
54
+ # Gets the markup class used by all instances of this Wiki.
55
+ # Default: Gollum::Markup
56
+ def markup_classes
57
+ @markup_classes ||=
58
+ if superclass.respond_to?(:markup_classes)
59
+ superclass.markup_classes
60
+ else
61
+ Hash.new(::Gollum::Markup)
62
+ end
63
+ end
64
+
65
+ # Gets the default markup class used by all instances of this Wiki.
66
+ # Kept for backwards compatibility until Gollum v2.x
67
+ def markup_class(language=:default)
68
+ markup_classes[language]
69
+ end
70
+
71
+ # Sets the default markup class used by all instances of this Wiki.
72
+ # Kept for backwards compatibility until Gollum v2.x
73
+ def markup_class=(default)
74
+ @markup_classes = Hash.new(default).update(markup_classes)
75
+ default
76
+ end
77
+
78
+ alias_method :default_markup_class, :markup_class
79
+ alias_method :default_markup_class=, :markup_class=
80
+
81
+ # Gets the default sanitization options for current pages used by
82
+ # instances of this Wiki.
83
+ def sanitization
84
+ if @sanitization.nil?
85
+ @sanitization = Sanitization.new
86
+ end
87
+ @sanitization
88
+ end
89
+
90
+ # Gets the default sanitization options for older page revisions used by
91
+ # instances of this Wiki.
92
+ def history_sanitization
93
+ if @history_sanitization.nil?
94
+ @history_sanitization = sanitization ?
95
+ sanitization.history_sanitization :
96
+ false
97
+ end
98
+ @history_sanitization
99
+ end
100
+ end
101
+
102
+ self.default_ref = 'master'
103
+ self.default_committer_name = 'Anonymous'
104
+ self.default_committer_email = 'anon@anon.com'
105
+
106
+ # The String base path to prefix to internal links. For example, when set
107
+ # to "/wiki", the page "Hobbit" will be linked as "/wiki/Hobbit". Defaults
108
+ # to "/".
109
+ attr_reader :base_path
110
+
111
+ # Gets the sanitization options for current pages used by this Wiki.
112
+ attr_reader :sanitization
113
+
114
+ # Gets the sanitization options for older page revisions used by this Wiki.
115
+ attr_reader :history_sanitization
116
+
117
+ # Gets the String ref in which all page files reside.
118
+ attr_reader :ref
119
+
120
+ # Gets the String directory in which all page files reside.
121
+ attr_reader :page_file_dir
122
+
123
+ # Public: Initialize a new Gollum Repo.
124
+ #
125
+ # path - The String path to the Git repository that holds the Gollum
126
+ # site.
127
+ # options - Optional Hash:
128
+ # :base_path - String base path for all Wiki links.
129
+ # Default: "/"
130
+ # :page_class - The page Class. Default: Gollum::Page
131
+ # :file_class - The file Class. Default: Gollum::File
132
+ # :markup_classes - A hash containing the markup Classes for each
133
+ # document type. Default: { Gollum::Markup }
134
+ # :sanitization - An instance of Sanitization.
135
+ # :page_file_dir - String the directory in which all page files reside
136
+ # :ref - String the repository ref to retrieve pages from
137
+ #
138
+ # Returns a fresh Gollum::Repo.
139
+ def initialize(path, options = {})
140
+ if path.is_a?(GitAccess)
141
+ options[:access] = path
142
+ path = path.path
143
+ end
144
+ @path = path
145
+ @page_file_dir = options[:page_file_dir]
146
+ @access = options[:access] || GitAccess.new(path, @page_file_dir)
147
+ @base_path = options[:base_path] || "/"
148
+ @page_class = options[:page_class] || self.class.page_class
149
+ @file_class = options[:file_class] || self.class.file_class
150
+ @markup_classes = options[:markup_classes] || self.class.markup_classes
151
+ @repo = @access.repo
152
+ @ref = options[:ref] || self.class.default_ref
153
+ @sanitization = options[:sanitization] || self.class.sanitization
154
+ @history_sanitization = options[:history_sanitization] ||
155
+ self.class.history_sanitization
156
+ end
157
+
158
+ # Public: check whether the wiki's git repo exists on the filesystem.
159
+ #
160
+ # Returns true if the repo exists, and false if it does not.
161
+ def exist?
162
+ @access.exist?
163
+ end
164
+
165
+ # Public: Get the formatted page for a given page name.
166
+ #
167
+ # name - The human or canonical String page name of the wiki page.
168
+ # version - The String version ID to find (default: @ref).
169
+ #
170
+ # Returns a Gollum::Page or nil if no matching page was found.
171
+ def page(name, version = @ref)
172
+ @page_class.new(self).find(name, version)
173
+ end
174
+
175
+ # Public: Get the static file for a given name.
176
+ #
177
+ # name - The full String pathname to the file.
178
+ # version - The String version ID to find (default: @ref).
179
+ #
180
+ # Returns a Gollum::File or nil if no matching file was found.
181
+ def file(name, version = @ref)
182
+ @file_class.new(self).find(name, version)
183
+ end
184
+
185
+ # Public: Lists all pages for this wiki.
186
+ #
187
+ # treeish - The String commit ID or ref to find (default: @ref)
188
+ #
189
+ # Returns an Array of Gollum::Page instances.
190
+ def pages(treeish = nil)
191
+ tree_list(treeish || @ref)
192
+ end
193
+
194
+ # Public: Returns the number of pages accessible from a commit
195
+ #
196
+ # ref - A String ref that is either a commit SHA or references one.
197
+ #
198
+ # Returns a Fixnum
199
+ def size(ref = nil)
200
+ tree_map_for(ref || @ref).inject(0) do |num, entry|
201
+ num + (@page_class.valid_page_name?(entry.name) ? 1 : 0)
202
+ end
203
+ rescue Grit::GitRuby::Repository::NoSuchShaFound
204
+ 0
205
+ end
206
+
207
+ # Public: All of the versions that have touched the Page.
208
+ #
209
+ # options - The options Hash:
210
+ # :page - The Integer page number (default: 1).
211
+ # :per_page - The Integer max count of items to return.
212
+ #
213
+ # Returns an Array of Grit::Commit.
214
+ def log(options = {})
215
+ @repo.log(@ref, nil, log_pagination_options(options))
216
+ end
217
+
218
+ # Public: Refreshes just the cached Git reference data. This should
219
+ # be called after every Gollum update.
220
+ #
221
+ # Returns nothing.
222
+ def clear_cache
223
+ @access.refresh
224
+ end
225
+
226
+ # Public: Creates a Sanitize instance using the Wiki's sanitization
227
+ # options.
228
+ #
229
+ # Returns a Sanitize instance.
230
+ def sanitizer
231
+ if options = sanitization
232
+ @sanitizer ||= options.to_sanitize
233
+ end
234
+ end
235
+
236
+ # Public: Creates a Sanitize instance using the Wiki's history sanitization
237
+ # options.
238
+ #
239
+ # Returns a Sanitize instance.
240
+ def history_sanitizer
241
+ if options = history_sanitization
242
+ @history_sanitizer ||= options.to_sanitize
243
+ end
244
+ end
245
+
246
+ #########################################################################
247
+ #
248
+ # Internal Methods
249
+ #
250
+ #########################################################################
251
+
252
+ # The Grit::Repo associated with the wiki.
253
+ #
254
+ # Returns the Grit::Repo.
255
+ attr_reader :repo
256
+
257
+ # The String path to the Git repository that holds the Gollum site.
258
+ #
259
+ # Returns the String path.
260
+ attr_reader :path
261
+
262
+ # Gets the page class used by all instances of this Wiki.
263
+ attr_reader :page_class
264
+
265
+ # Gets the file class used by all instances of this Wiki.
266
+ attr_reader :file_class
267
+
268
+ # Gets the markup class used by all instances of this Wiki.
269
+ attr_reader :markup_classes
270
+
271
+ # Normalize the data.
272
+ #
273
+ # data - The String data to be normalized.
274
+ #
275
+ # Returns the normalized data String.
276
+ def normalize(data)
277
+ data.gsub(/\r/, '')
278
+ end
279
+
280
+ # Assemble a Page's filename from its name and format.
281
+ #
282
+ # name - The String name of the page (may be in human format).
283
+ # format - The Symbol format of the page.
284
+ #
285
+ # Returns the String filename.
286
+ def page_file_name(name, format)
287
+ ext = @page_class.format_to_ext(format)
288
+ @page_class.cname(name) + '.' + ext
289
+ end
290
+
291
+ # Fill an array with a list of pages.
292
+ #
293
+ # ref - A String ref that is either a commit SHA or references one.
294
+ #
295
+ # Returns a flat Array of Gollum::Page instances.
296
+ def tree_list(ref)
297
+ if sha = @access.ref_to_sha(ref)
298
+ commit = @access.commit(sha)
299
+ tree_map_for(sha).inject([]) do |list, entry|
300
+ next list unless @page_class.valid_page_name?(entry.name)
301
+ list << entry.page(self, commit)
302
+ end
303
+ else
304
+ []
305
+ end
306
+ end
307
+
308
+ # Creates a reverse diff for the given SHAs on the given Gollum::Page.
309
+ #
310
+ # page - The Gollum::Page to scope the patch to, or a String Path.
311
+ # sha1 - String SHA1 of the earlier parent if two SHAs are given,
312
+ # or the child.
313
+ # sha2 - Optional String SHA1 of the child.
314
+ #
315
+ # Returns a String of the reverse Diff to apply.
316
+ def full_reverse_diff_for(page, sha1, sha2 = nil)
317
+ sha1, sha2 = "#{sha1}^", sha1 if sha2.nil?
318
+ args = [{:R => true}, sha1, sha2]
319
+ if page
320
+ args << '--' << (page.respond_to?(:path) ? page.path : page.to_s)
321
+ end
322
+ repo.git.native(:diff, *args)
323
+ end
324
+
325
+ # Creates a reverse diff for the given SHAs.
326
+ #
327
+ # sha1 - String SHA1 of the earlier parent if two SHAs are given,
328
+ # or the child.
329
+ # sha2 - Optional String SHA1 of the child.
330
+ #
331
+ # Returns a String of the reverse Diff to apply.
332
+ def full_reverse_diff(sha1, sha2 = nil)
333
+ full_reverse_diff_for(nil, sha1, sha2)
334
+ end
335
+
336
+ # Gets the default name for commits.
337
+ #
338
+ # Returns the String name.
339
+ def default_committer_name
340
+ @default_committer_name ||= \
341
+ @repo.config['user.name'] || self.class.default_committer_name
342
+ end
343
+
344
+ # Gets the default email for commits.
345
+ #
346
+ # Returns the String email address.
347
+ def default_committer_email
348
+ @default_committer_email ||= \
349
+ @repo.config['user.email'] || self.class.default_committer_email
350
+ end
351
+
352
+ # Gets the commit object for the given ref or sha.
353
+ #
354
+ # ref - A string ref or SHA pointing to a valid commit.
355
+ #
356
+ # Returns a Grit::Commit instance.
357
+ def commit_for(ref)
358
+ @access.commit(ref)
359
+ rescue Grit::GitRuby::Repository::NoSuchShaFound
360
+ end
361
+
362
+ # Finds a full listing of files and their blob SHA for a given ref. Each
363
+ # listing is cached based on its actual commit SHA.
364
+ #
365
+ # ref - A String ref that is either a commit SHA or references one.
366
+ #
367
+ # Returns an Array of BlobEntry instances.
368
+ def tree_map_for(ref)
369
+ @access.tree(ref)
370
+ rescue Grit::GitRuby::Repository::NoSuchShaFound
371
+ []
372
+ end
373
+
374
+ def inspect
375
+ %(#<#{self.class.name}:#{object_id} #{@repo.path}>)
376
+ end
377
+ end
378
+ end