gollum-lib 4.0.3-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +15 -0
  2. data/Gemfile +3 -0
  3. data/HISTORY.md +11 -0
  4. data/LICENSE +21 -0
  5. data/README.md +286 -0
  6. data/Rakefile +187 -0
  7. data/docs/sanitization.md +33 -0
  8. data/gemspec.rb +100 -0
  9. data/gollum-lib.gemspec +4 -0
  10. data/gollum-lib_java.gemspec +4 -0
  11. data/lib/gollum-lib.rb +64 -0
  12. data/lib/gollum-lib/blob_entry.rb +95 -0
  13. data/lib/gollum-lib/committer.rb +243 -0
  14. data/lib/gollum-lib/file.rb +158 -0
  15. data/lib/gollum-lib/file_view.rb +155 -0
  16. data/lib/gollum-lib/filter.rb +78 -0
  17. data/lib/gollum-lib/filter/code.rb +145 -0
  18. data/lib/gollum-lib/filter/macro.rb +57 -0
  19. data/lib/gollum-lib/filter/metadata.rb +29 -0
  20. data/lib/gollum-lib/filter/plain_text.rb +16 -0
  21. data/lib/gollum-lib/filter/remote_code.rb +63 -0
  22. data/lib/gollum-lib/filter/render.rb +20 -0
  23. data/lib/gollum-lib/filter/sanitize.rb +18 -0
  24. data/lib/gollum-lib/filter/tags.rb +320 -0
  25. data/lib/gollum-lib/filter/toc.rb +109 -0
  26. data/lib/gollum-lib/filter/wsd.rb +54 -0
  27. data/lib/gollum-lib/git_access.rb +247 -0
  28. data/lib/gollum-lib/gitcode.rb +48 -0
  29. data/lib/gollum-lib/helpers.rb +13 -0
  30. data/lib/gollum-lib/hook.rb +35 -0
  31. data/lib/gollum-lib/macro.rb +43 -0
  32. data/lib/gollum-lib/macro/all_pages.rb +11 -0
  33. data/lib/gollum-lib/markup.rb +197 -0
  34. data/lib/gollum-lib/markups.rb +20 -0
  35. data/lib/gollum-lib/page.rb +491 -0
  36. data/lib/gollum-lib/pagination.rb +62 -0
  37. data/lib/gollum-lib/sanitization.rb +176 -0
  38. data/lib/gollum-lib/version.rb +5 -0
  39. data/lib/gollum-lib/wiki.rb +925 -0
  40. data/licenses/licenses.txt +6 -0
  41. metadata +410 -0
@@ -0,0 +1,109 @@
1
+ # Inserts header anchors and creates TOC
2
+ class Gollum::Filter::TOC < Gollum::Filter
3
+ def extract(data)
4
+ data
5
+ end
6
+
7
+ def process(data)
8
+
9
+ @doc = Nokogiri::HTML::DocumentFragment.parse(data)
10
+ @toc = nil
11
+ @anchor_names = {}
12
+ @current_ancestors = []
13
+
14
+ if @markup.sub_page && @markup.parent_page
15
+ @toc = @markup.parent_page.toc_data
16
+ else
17
+ @doc.css('h1,h2,h3,h4,h5,h6').each_with_index do |header, i|
18
+ next if header.content.empty?
19
+ # omit the first H1 (the page title) from the TOC if so configured
20
+ next if (i == 0 && header.name =~ /[Hh]1/) && @markup.wiki && @markup.wiki.h1_title
21
+
22
+ anchor_name = generate_anchor_name(header)
23
+
24
+ add_anchor_to_header header, anchor_name
25
+ add_entry_to_toc header, anchor_name
26
+ end
27
+
28
+ @toc = @toc.to_xml(@markup.to_xml_opts) if @toc != nil
29
+ data = @doc.to_xml(@markup.to_xml_opts)
30
+
31
+ end
32
+
33
+ @markup.toc = @toc
34
+ data.gsub("[[_TOC_]]") do
35
+ @toc.nil? ? '' : @toc
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ # Generates the anchor name from the given header element
42
+ # removing all non alphanumeric characters, replacing them
43
+ # with single dashes.
44
+ #
45
+ # Generates heading ancestry prefixing the headings
46
+ # ancestor names to the generated name.
47
+ #
48
+ # Prefixes duplicate anchors with an index
49
+ def generate_anchor_name(header)
50
+ name = header.content
51
+ level = header.name.gsub(/[hH]/, '').to_i
52
+
53
+ # normalize the header name
54
+ name.gsub!(/[^\d\w\u00C0-\u1FFF\u2C00-\uD7FF]/, "-")
55
+ name.gsub!(/-+/, "-")
56
+ name.gsub!(/^-/, "")
57
+ name.gsub!(/-$/, "")
58
+ name.downcase!
59
+
60
+ @current_ancestors[level - 1] = name
61
+ @current_ancestors = @current_ancestors.take(level)
62
+ anchor_name = @current_ancestors.compact.join("_")
63
+
64
+ # Ensure duplicate anchors have a unique prefix or the toc will break
65
+ index = increment_anchor_index(anchor_name)
66
+ anchor_name = "#{index}-#{anchor_name}" unless index.zero? # if the index is zero this name is unique
67
+
68
+ anchor_name
69
+ end
70
+
71
+ # Creates an anchor element with the given name and adds it before
72
+ # the given header element.
73
+ def add_anchor_to_header(header, name)
74
+ anchor_element = %Q(<a class="anchor" id="#{name}" href="##{name}"><i class="fa fa-link"></i></a>)
75
+ header.children.before anchor_element # Add anchor element before the header
76
+ end
77
+
78
+ # Adds an entry to the TOC for the given header. The generated entry
79
+ # is a link to the given anchor name
80
+ def add_entry_to_toc(header, name)
81
+ @toc ||= Nokogiri::XML::DocumentFragment.parse('<div class="toc"><div class="toc-title">Table of Contents</div></div>')
82
+ tail ||= @toc.child
83
+ tail_level ||= 0
84
+
85
+ level = header.name.gsub(/[hH]/, '').to_i
86
+
87
+ while tail_level < level
88
+ node = Nokogiri::XML::Node.new('ul', @doc)
89
+ tail = tail.add_child(node)
90
+ tail_level += 1
91
+ end
92
+
93
+ while tail_level > level
94
+ tail = tail.parent
95
+ tail_level -= 1
96
+ end
97
+ node = Nokogiri::XML::Node.new('li', @doc)
98
+ # % -> %25 so anchors work on Firefox. See issue #475
99
+ node.add_child(%Q{<a href="##{name}">#{header.content}</a>})
100
+ tail.add_child(node)
101
+ end
102
+
103
+ # Increments the number of anchors with the given name
104
+ # and returns the current index
105
+ def increment_anchor_index(name)
106
+ @anchor_names = {} if @anchor_names.nil?
107
+ @anchor_names[name].nil? ? @anchor_names[name] = 0 : @anchor_names[name] += 1
108
+ end
109
+ end
@@ -0,0 +1,54 @@
1
+ # ~*~ encoding: utf-8 ~*~
2
+ require 'net/http'
3
+ require 'uri'
4
+ require 'open-uri'
5
+
6
+ # Web Sequence Diagrams
7
+ #
8
+ # Render an inline web sequence diagram by sending the WSD code through the
9
+ # online renderer available from www.websequencediagrams.com.
10
+ #
11
+ class Gollum::Filter::WSD < Gollum::Filter
12
+ WSD_URL = "http://www.websequencediagrams.com/index.php"
13
+
14
+ # Extract all sequence diagram blocks into the map and replace with
15
+ # placeholders.
16
+ def extract(data)
17
+ return data if @markup.format == :txt
18
+ data.gsub(/^\{\{\{\{\{\{ ?(.+?)\r?\n(.+?)\r?\n\}\}\}\}\}\}\r?$/m) do
19
+ id = Digest::SHA1.hexdigest($2)
20
+ @map[id] = { :style => $1, :code => $2 }
21
+ id
22
+ end
23
+ end
24
+
25
+ # Process all diagrams from the map and replace the placeholders with
26
+ # the final HTML.
27
+ #
28
+ # data - The String data (with placeholders).
29
+ #
30
+ # Returns the marked up String data.
31
+ def process(data)
32
+ @map.each do |id, spec|
33
+ data.gsub!(id) do
34
+ render_wsd(spec[:code], spec[:style])
35
+ end
36
+ end
37
+ data
38
+ end
39
+
40
+ private
41
+ # Render the sequence diagram on the remote server.
42
+ #
43
+ # Returns an <img> tag to the rendered image, or an HTML error.
44
+ def render_wsd(code, style)
45
+ response = Net::HTTP.post_form(URI.parse(WSD_URL), 'style' => style, 'message' => code)
46
+ if response.body =~ /img: "(.+)"/
47
+ url = "//www.websequencediagrams.com/#{$1}"
48
+ "<img src=\"#{url}\" />"
49
+ else
50
+ puts response.body
51
+ html_error("Sorry, unable to render sequence diagram at this time.")
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,247 @@
1
+ # ~*~ encoding: utf-8 ~*~
2
+ module Gollum
3
+ # Controls all access to the Git objects from Gollum. Extend this class to
4
+ # add custom caching for special cases.
5
+ class GitAccess
6
+ # Initializes the GitAccess instance.
7
+ #
8
+ # path - The String path to the Git repository that holds the
9
+ # Gollum site.
10
+ # page_file_dir - String the directory in which all page files reside
11
+ #
12
+ # Returns this instance.
13
+ def initialize(path, page_file_dir = nil, bare = nil)
14
+ @page_file_dir = page_file_dir
15
+ @path = path
16
+ @repo = Gollum::Git::Repo.new(path, { :is_bare => bare })
17
+ clear
18
+ end
19
+
20
+ # Public: Determines whether the Git repository exists on disk.
21
+ #
22
+ # Returns true if it exists, or false.
23
+ def exist?
24
+ @repo.git.exist?
25
+ end
26
+
27
+ # Public: Converts a given Git reference to a SHA, using the cache if
28
+ # available.
29
+ #
30
+ # ref - a String Git reference (ex: "master")
31
+ #
32
+ # Returns a String, or nil if the ref isn't found.
33
+ def ref_to_sha(ref)
34
+ ref = ref.to_s
35
+ return if ref.empty?
36
+ sha =
37
+ if sha?(ref)
38
+ ref
39
+ else
40
+ get_cache(:ref, ref) { ref_to_sha!(ref) }
41
+ end.to_s
42
+ sha.empty? ? nil : sha
43
+ end
44
+
45
+ # Public: Gets a recursive list of Git blobs for the whole tree at the
46
+ # given commit.
47
+ #
48
+ # ref - A String Git reference or Git SHA to a commit.
49
+ #
50
+ # Returns an Array of BlobEntry instances.
51
+ def tree(ref)
52
+ if sha = ref_to_sha(ref)
53
+ get_cache(:tree, sha) { tree!(sha) }
54
+ else
55
+ []
56
+ end
57
+ end
58
+
59
+ # Public: Fetches the contents of the Git blob at the given SHA.
60
+ #
61
+ # sha - A String Git SHA.
62
+ #
63
+ # Returns the String content of the blob.
64
+ def blob(sha)
65
+ cat_file!(sha)
66
+ end
67
+
68
+ # Public: Looks up the Git commit using the given Git SHA or ref.
69
+ #
70
+ # ref - A String Git SHA or ref.
71
+ #
72
+ # Returns a Gollum::Git::Commit.
73
+ def commit(ref)
74
+ if sha?(ref)
75
+ get_cache(:commit, ref) { commit!(ref) }
76
+ else
77
+ if sha = get_cache(:ref, ref)
78
+ commit(sha)
79
+ else
80
+ if cm = commit!(ref)
81
+ set_cache(:ref, ref, cm.id)
82
+ set_cache(:commit, cm.id, cm)
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ # Public: Clears all of the cached data that this GitAccess is tracking.
89
+ #
90
+ # Returns nothing.
91
+ def clear
92
+ @ref_map = {}
93
+ @tree_map = {}
94
+ @commit_map = {}
95
+ end
96
+
97
+ # Public: Refreshes just the cached Git reference data. This should
98
+ # be called after every Gollum update.
99
+ #
100
+ # Returns nothing.
101
+ def refresh
102
+ @ref_map.clear
103
+ end
104
+
105
+ #########################################################################
106
+ #
107
+ # Internal Methods
108
+ #
109
+ #########################################################################
110
+
111
+ # Gets the String path to the Git repository.
112
+ attr_reader :path
113
+
114
+ # Gets the Gollum::Git::Repo instance for the Git repository.
115
+ attr_reader :repo
116
+
117
+ # Gets a Hash cache of refs to commit SHAs.
118
+ #
119
+ # {"master" => "abc123", ...}
120
+ #
121
+ attr_reader :ref_map
122
+
123
+ # Gets a Hash cache of commit SHAs to a recursive tree of blobs.
124
+ #
125
+ # {"abc123" => [<BlobEntry>, <BlobEntry>]}
126
+ #
127
+ attr_reader :tree_map
128
+
129
+ # Gets a Hash cache of commit SHAs to the Gollum::Git::Commit instance.
130
+ #
131
+ # {"abcd123" => <Gollum::Git::Commit>}
132
+ #
133
+ attr_reader :commit_map
134
+
135
+ # Checks to see if the given String is a 40 character hex SHA.
136
+ #
137
+ # str - Possible String SHA.
138
+ #
139
+ # Returns true if the String is a SHA, or false.
140
+ def sha?(str)
141
+ !!(str =~ /^[0-9a-f]{40}$/)
142
+ end
143
+
144
+ # Looks up the Git SHA for the given Git ref.
145
+ #
146
+ # ref - String Git ref.
147
+ #
148
+ # Returns a String SHA.
149
+ def ref_to_sha!(ref)
150
+ commit = @repo.commit(ref)
151
+ commit ? commit.id : nil
152
+ end
153
+
154
+ # Looks up the Git blobs for a given commit.
155
+ #
156
+ # sha - String commit SHA.
157
+ #
158
+ # Returns an Array of BlobEntry instances.
159
+ def tree!(sha)
160
+ tree = @repo.lstree(sha, { :recursive => true })
161
+ items = []
162
+ tree.each do |entry|
163
+ if entry[:type] == 'blob'
164
+ items << BlobEntry.new(entry[:sha], entry[:path], entry[:size], entry[:mode].to_i(8))
165
+ end
166
+ end
167
+ if dir = @page_file_dir
168
+ regex = /^#{dir}\//
169
+ items.select { |i| i.path =~ regex }
170
+ else
171
+ items
172
+ end
173
+ end
174
+
175
+ # Reads the content from the Git db at the given SHA.
176
+ #
177
+ # sha - The String SHA.
178
+ #
179
+ # Returns the String content of the Git object.
180
+ def cat_file!(sha)
181
+ @repo.git.cat_file({ :p => true }, sha)
182
+ end
183
+
184
+ # Reads a Git commit.
185
+ #
186
+ # sha - The string SHA of the Git commit.
187
+ #
188
+ # Returns a Gollum::Git::Commit.
189
+ def commit!(sha)
190
+ @repo.commit(sha)
191
+ end
192
+
193
+ # Attempts to get the given data from a cache. If it doesn't exist, it'll
194
+ # pass the results of the yielded block to the cache for future accesses.
195
+ #
196
+ # name - The cache prefix used in building the full cache key.
197
+ # key - The unique cache key suffix, usually a String Git SHA.
198
+ #
199
+ # Yields a block to pass to the cache.
200
+ # Returns the cached result.
201
+ def get_cache(name, key)
202
+ cache = instance_variable_get("@#{name}_map")
203
+ value = cache[key]
204
+ if value.nil? && block_given?
205
+ set_cache(name, key, value = yield)
206
+ end
207
+ value == :_nil ? nil : value
208
+ end
209
+
210
+ # Writes some data to the internal cache.
211
+ #
212
+ # name - The cache prefix used in building the full cache key.
213
+ # key - The unique cache key suffix, usually a String Git SHA.
214
+ # value - The value to write to the cache.
215
+ #
216
+ # Returns nothing.
217
+ def set_cache(name, key, value)
218
+ cache = instance_variable_get("@#{name}_map")
219
+ cache[key] = value || :_nil
220
+ end
221
+
222
+ # Parses a line of output from the `ls-tree` command.
223
+ #
224
+ # line - A String line of output:
225
+ # "100644 blob 839c2291b30495b9a882c17d08254d3c90d8fb53 Home.md"
226
+ #
227
+ # Returns an Array of BlobEntry instances.
228
+ def parse_tree_line(line)
229
+ mode, type, sha, size, *name = line.split(/\s+/)
230
+ BlobEntry.new(sha, name.join(' '), size.to_i, mode.to_i(8))
231
+ end
232
+
233
+ # Decode octal sequences (\NNN) in tree path names.
234
+ #
235
+ # path - String path name.
236
+ #
237
+ # Returns a decoded String.
238
+ def decode_git_path(path)
239
+ if path[0] == ?" && path[-1] == ?"
240
+ path = path[1...-1]
241
+ path.gsub!(/\\\d{3}/) { |m| m[1..-1].to_i(8).chr }
242
+ end
243
+ path.gsub!(/\\[rn"\\]/) { |m| eval(%("#{m.to_s}")) }
244
+ path
245
+ end
246
+ end
247
+ end
@@ -0,0 +1,48 @@
1
+ # ~*~ encoding: utf-8 ~*~
2
+ require 'net/http'
3
+ require 'net/https' # ruby 1.8.7 fix, remove at upgrade
4
+ require 'uri'
5
+ require 'open-uri'
6
+
7
+ module Gollum
8
+ class Gitcode
9
+ def initialize path
10
+ raise(ArgumentError, 'path is nil or empty') if path.nil? or path.empty?
11
+
12
+ @uri = URI::HTTP.build({
13
+ :path => self.unchomp(path),
14
+ :host => 'raw.github.com',
15
+ :scheme => 'https',
16
+ :port => 443 })
17
+ end
18
+
19
+ def contents
20
+ @contents ||= self.req @uri
21
+ end
22
+
23
+ def unchomp p
24
+ return p if p.nil?
25
+ p[0] == '/' ? p : ('/' + p)
26
+ end
27
+
28
+ def req uri, cut = 1
29
+ return "Too many redirects or retries" if cut >= 10
30
+ http = Net::HTTP.new uri.host, uri.port
31
+ http.use_ssl = true
32
+ resp = http.get uri.path, {
33
+ 'Accept' => 'text/plain',
34
+ 'Cache-Control' => 'no-cache',
35
+ 'Connection' => 'keep-alive',
36
+ 'Host' => uri.host,
37
+ 'User-Agent' => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0'
38
+ }
39
+ code = resp.code.to_i
40
+ return resp.body if code == 200
41
+ return "Not Found" if code == 404
42
+ return "Unhandled Response Code #{code}" unless code == 304 or not resp.header['location'].nil?
43
+ loc = URI.parse resp.header['location']
44
+ uri2 = loc.relative?() ? (uri + loc) : loc # overloads (+)
45
+ return req uri2, (cut + 1)
46
+ end
47
+ end
48
+ end