gollum-lib 4.0.3-java
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.
- checksums.yaml +15 -0
- data/Gemfile +3 -0
- data/HISTORY.md +11 -0
- data/LICENSE +21 -0
- data/README.md +286 -0
- data/Rakefile +187 -0
- data/docs/sanitization.md +33 -0
- data/gemspec.rb +100 -0
- data/gollum-lib.gemspec +4 -0
- data/gollum-lib_java.gemspec +4 -0
- data/lib/gollum-lib.rb +64 -0
- data/lib/gollum-lib/blob_entry.rb +95 -0
- data/lib/gollum-lib/committer.rb +243 -0
- data/lib/gollum-lib/file.rb +158 -0
- data/lib/gollum-lib/file_view.rb +155 -0
- data/lib/gollum-lib/filter.rb +78 -0
- data/lib/gollum-lib/filter/code.rb +145 -0
- data/lib/gollum-lib/filter/macro.rb +57 -0
- data/lib/gollum-lib/filter/metadata.rb +29 -0
- data/lib/gollum-lib/filter/plain_text.rb +16 -0
- data/lib/gollum-lib/filter/remote_code.rb +63 -0
- data/lib/gollum-lib/filter/render.rb +20 -0
- data/lib/gollum-lib/filter/sanitize.rb +18 -0
- data/lib/gollum-lib/filter/tags.rb +320 -0
- data/lib/gollum-lib/filter/toc.rb +109 -0
- data/lib/gollum-lib/filter/wsd.rb +54 -0
- data/lib/gollum-lib/git_access.rb +247 -0
- data/lib/gollum-lib/gitcode.rb +48 -0
- data/lib/gollum-lib/helpers.rb +13 -0
- data/lib/gollum-lib/hook.rb +35 -0
- data/lib/gollum-lib/macro.rb +43 -0
- data/lib/gollum-lib/macro/all_pages.rb +11 -0
- data/lib/gollum-lib/markup.rb +197 -0
- data/lib/gollum-lib/markups.rb +20 -0
- data/lib/gollum-lib/page.rb +491 -0
- data/lib/gollum-lib/pagination.rb +62 -0
- data/lib/gollum-lib/sanitization.rb +176 -0
- data/lib/gollum-lib/version.rb +5 -0
- data/lib/gollum-lib/wiki.rb +925 -0
- data/licenses/licenses.txt +6 -0
- 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
|