rtfmd 0.10301.17
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.md +93 -0
- data/LICENSE +21 -0
- data/README.md +393 -0
- data/bin/rtfm +0 -0
- data/bin/rtfmd +4 -0
- data/config/rtfmd.ru +33 -0
- data/docs/sanitization.md +32 -0
- data/lib/gollum.rb +39 -0
- data/lib/gollum/blob_entry.rb +78 -0
- data/lib/gollum/committer.rb +217 -0
- data/lib/gollum/file.rb +64 -0
- data/lib/gollum/frontend/app.rb +96 -0
- data/lib/gollum/frontend/indexapp.rb +17 -0
- data/lib/gollum/frontend/public/css/gollum.css +660 -0
- data/lib/gollum/frontend/public/css/ie7.css +69 -0
- data/lib/gollum/frontend/public/css/ronn.css +40 -0
- data/lib/gollum/frontend/public/css/template.css +381 -0
- data/lib/gollum/frontend/public/images/icon-sprite.png +0 -0
- data/lib/gollum/frontend/public/javascript/gollum.js +137 -0
- data/lib/gollum/frontend/public/javascript/gollum.placeholder.js +54 -0
- data/lib/gollum/frontend/public/javascript/jquery.color.js +123 -0
- data/lib/gollum/frontend/public/javascript/jquery.js +7179 -0
- data/lib/gollum/frontend/templates/error.mustache +8 -0
- data/lib/gollum/frontend/templates/index.mustache +25 -0
- data/lib/gollum/frontend/templates/layout.mustache +28 -0
- data/lib/gollum/frontend/templates/page.mustache +34 -0
- data/lib/gollum/frontend/templates/pages.mustache +31 -0
- data/lib/gollum/frontend/views/error.rb +7 -0
- data/lib/gollum/frontend/views/index.rb +21 -0
- data/lib/gollum/frontend/views/layout.rb +28 -0
- data/lib/gollum/frontend/views/page.rb +53 -0
- data/lib/gollum/frontend/views/pages.rb +19 -0
- data/lib/gollum/git_access.rb +248 -0
- data/lib/gollum/markup.rb +389 -0
- data/lib/gollum/page.rb +374 -0
- data/lib/gollum/pagination.rb +61 -0
- data/lib/gollum/sanitization.rb +161 -0
- data/lib/gollum/wiki.rb +378 -0
- data/rtfmd.gemspec +47 -0
- metadata +291 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
<div id="wiki-wrapper" class="results">
|
2
|
+
<div id="head">
|
3
|
+
<h1>{{title}}</h1>
|
4
|
+
</div>
|
5
|
+
<div id="results">
|
6
|
+
|
7
|
+
{{#has_roots}}
|
8
|
+
<ul>
|
9
|
+
{{#roots}}
|
10
|
+
<li>
|
11
|
+
<a href="{{root}}">{{wiki}}</a>
|
12
|
+
</li>
|
13
|
+
{{/roots}}
|
14
|
+
</ul>
|
15
|
+
{{/has_roots}}
|
16
|
+
|
17
|
+
{{#no_roots}}
|
18
|
+
<p id="no-results">
|
19
|
+
There are no wikis.
|
20
|
+
</p>
|
21
|
+
{{/no_roots}}
|
22
|
+
|
23
|
+
</div>
|
24
|
+
</div>
|
25
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta http-equiv="Content-type" content="text/html;charset=utf-8">
|
5
|
+
<link rel="stylesheet" type="text/css" href="{{base_path}}css/gollum.css" media="all">
|
6
|
+
<link rel="stylesheet" type="text/css" href="{{base_path}}css/template.css" media="all">
|
7
|
+
<link rel="stylesheet" type="text/css" href="{{base_path}}css/ronn.css" media="all">
|
8
|
+
|
9
|
+
<!--[if IE 7]>
|
10
|
+
<link rel="stylesheet" type="text/css" href="{{base_path}}css/ie7.css" media="all">
|
11
|
+
<![endif]-->
|
12
|
+
|
13
|
+
<script type="text/javascript" src="{{base_path}}javascript/jquery.js"></script>
|
14
|
+
<script type="text/javascript" src="{{base_path}}javascript/gollum.js"></script>
|
15
|
+
<script type="text/javascript" src="{{base_path}}javascript/gollum.placeholder.js"></script>
|
16
|
+
</head>
|
17
|
+
<body id='manpage'>
|
18
|
+
<div class='mp' id='man'>
|
19
|
+
|
20
|
+
<div class='man-navigation' style='display:none'>
|
21
|
+
</div>
|
22
|
+
|
23
|
+
{{{yield}}}
|
24
|
+
|
25
|
+
</div>
|
26
|
+
|
27
|
+
</body>
|
28
|
+
</html>
|
@@ -0,0 +1,34 @@
|
|
1
|
+
<div id="wiki-wrapper" class="page">
|
2
|
+
<div id="head">
|
3
|
+
<ul class="actions">
|
4
|
+
<li class="minibutton"><a href="{{base_path}}"
|
5
|
+
class="action-home-page">Home</a></li>
|
6
|
+
<li class="minibutton"><a href="{{base_path}}pages"
|
7
|
+
class="action-all-pages">All Pages</a></li>
|
8
|
+
<li class="minibutton"><a href="{{rtfm_root}}"
|
9
|
+
class="action-all-projects">All Projects</a></li>
|
10
|
+
</ul>
|
11
|
+
</div>
|
12
|
+
<div id="wiki-content">
|
13
|
+
<div class="wrap {{#has_footer}} has-footer {{/has_footer}} {{#has_sidebar}} has-rightbar{{/has_sidebar}}">
|
14
|
+
<div id="wiki-body" class="gollum-{{format}}-content">
|
15
|
+
<div id="template">
|
16
|
+
{{{content}}}
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
{{#has_sidebar}}
|
20
|
+
<div id="wiki-rightbar" class="gollum-{{sidebar_format}}-content">
|
21
|
+
{{{sidebar_content}}}
|
22
|
+
</div>
|
23
|
+
{{/has_sidebar}}
|
24
|
+
{{#has_footer}}
|
25
|
+
<div id="wiki-footer" class="gollum-{{footer_format}}-content">
|
26
|
+
<div id="footer-content">
|
27
|
+
{{{footer_content}}}
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
{{/has_footer}}
|
31
|
+
</div>
|
32
|
+
|
33
|
+
</div>
|
34
|
+
</div>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<div id="wiki-wrapper" class="results">
|
2
|
+
<div id="head">
|
3
|
+
<h1>{{title}}</h1>
|
4
|
+
<ul class="actions">
|
5
|
+
<li class="minibutton"><a href="{{base_path}}"
|
6
|
+
class="action-home-page">Home</a></li>
|
7
|
+
</ul>
|
8
|
+
</div>
|
9
|
+
<div id="results">
|
10
|
+
|
11
|
+
{{#has_results}}
|
12
|
+
<ul>
|
13
|
+
{{#results}}
|
14
|
+
<li>
|
15
|
+
<a href="{{base_path}}{{name}}">{{name}}</a>
|
16
|
+
</li>
|
17
|
+
{{/results}}
|
18
|
+
</ul>
|
19
|
+
{{/has_results}}
|
20
|
+
|
21
|
+
{{#no_results}}
|
22
|
+
<p id="no-results">
|
23
|
+
There are no pages in <strong>{{ref}}</strong>.
|
24
|
+
</p>
|
25
|
+
{{/no_results}}
|
26
|
+
|
27
|
+
</div>
|
28
|
+
<div id="footer">
|
29
|
+
</div>
|
30
|
+
</div>
|
31
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module Precious
|
4
|
+
module Views
|
5
|
+
class Layout < Mustache
|
6
|
+
include Rack::Utils
|
7
|
+
alias_method :h, :escape_html
|
8
|
+
|
9
|
+
attr_reader :name
|
10
|
+
|
11
|
+
def escaped_name
|
12
|
+
CGI.escape(@name)
|
13
|
+
end
|
14
|
+
|
15
|
+
def title
|
16
|
+
"Home"
|
17
|
+
end
|
18
|
+
|
19
|
+
def base_path
|
20
|
+
@base_path
|
21
|
+
end
|
22
|
+
|
23
|
+
def rtfm_root
|
24
|
+
@rtfm_root
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Precious
|
2
|
+
module Views
|
3
|
+
class Page < Layout
|
4
|
+
attr_reader :content, :page, :footer
|
5
|
+
DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
|
6
|
+
DEFAULT_AUTHOR = 'you'
|
7
|
+
|
8
|
+
def title
|
9
|
+
@page.title
|
10
|
+
end
|
11
|
+
|
12
|
+
def format
|
13
|
+
@page.format.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
def author
|
17
|
+
return DEFAULT_AUTHOR unless @page.version
|
18
|
+
@page.version.author.name
|
19
|
+
end
|
20
|
+
|
21
|
+
def date
|
22
|
+
return Time.now.strftime(DATE_FORMAT) unless @page.version
|
23
|
+
@page.version.authored_date.strftime(DATE_FORMAT)
|
24
|
+
end
|
25
|
+
|
26
|
+
def has_footer
|
27
|
+
@footer = (@page.footer || false) if @footer.nil?
|
28
|
+
!!@footer
|
29
|
+
end
|
30
|
+
|
31
|
+
def footer_content
|
32
|
+
has_footer && @footer.formatted_data
|
33
|
+
end
|
34
|
+
|
35
|
+
def footer_format
|
36
|
+
has_footer && @footer.format.to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
def has_sidebar
|
40
|
+
@sidebar = (@page.sidebar || false) if @sidebar.nil?
|
41
|
+
!!@sidebar
|
42
|
+
end
|
43
|
+
|
44
|
+
def sidebar_content
|
45
|
+
has_sidebar && @sidebar.formatted_data
|
46
|
+
end
|
47
|
+
|
48
|
+
def sidebar_format
|
49
|
+
has_sidebar && @sidebar.format.to_s
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Precious
|
2
|
+
module Views
|
3
|
+
class Pages < Layout
|
4
|
+
attr_reader :results, :ref
|
5
|
+
|
6
|
+
def title
|
7
|
+
"All pages in #{@ref}"
|
8
|
+
end
|
9
|
+
|
10
|
+
def has_results
|
11
|
+
!@results.empty?
|
12
|
+
end
|
13
|
+
|
14
|
+
def no_results
|
15
|
+
@results.empty?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,248 @@
|
|
1
|
+
module Gollum
|
2
|
+
# Controls all access to the Git objects from Gollum. Extend this class to
|
3
|
+
# add custom caching for special cases.
|
4
|
+
class GitAccess
|
5
|
+
# Initializes the GitAccess instance.
|
6
|
+
#
|
7
|
+
# path - The String path to the Git repository that holds the
|
8
|
+
# Gollum site.
|
9
|
+
# page_file_dir - String the directory in which all page files reside
|
10
|
+
#
|
11
|
+
# Returns this instance.
|
12
|
+
def initialize(path, page_file_dir = nil)
|
13
|
+
@page_file_dir = page_file_dir
|
14
|
+
@path = path
|
15
|
+
@repo = Grit::Repo.new(path)
|
16
|
+
clear
|
17
|
+
end
|
18
|
+
|
19
|
+
# Public: Determines whether the Git repository exists on disk.
|
20
|
+
#
|
21
|
+
# Returns true if it exists, or false.
|
22
|
+
def exist?
|
23
|
+
@repo.git.exist?
|
24
|
+
end
|
25
|
+
|
26
|
+
# Public: Converts a given Git reference to a SHA, using the cache if
|
27
|
+
# available.
|
28
|
+
#
|
29
|
+
# ref - a String Git reference (ex: "master")
|
30
|
+
#
|
31
|
+
# Returns a String, or nil if the ref isn't found.
|
32
|
+
def ref_to_sha(ref)
|
33
|
+
ref = ref.to_s
|
34
|
+
return if ref.empty?
|
35
|
+
sha =
|
36
|
+
if sha?(ref)
|
37
|
+
ref
|
38
|
+
else
|
39
|
+
get_cache(:ref, ref) { ref_to_sha!(ref) }
|
40
|
+
end.to_s
|
41
|
+
sha.empty? ? nil : sha
|
42
|
+
end
|
43
|
+
|
44
|
+
# Public: Gets a recursive list of Git blobs for the whole tree at the
|
45
|
+
# given commit.
|
46
|
+
#
|
47
|
+
# ref - A String Git reference or Git SHA to a commit.
|
48
|
+
#
|
49
|
+
# Returns an Array of BlobEntry instances.
|
50
|
+
def tree(ref)
|
51
|
+
if sha = ref_to_sha(ref)
|
52
|
+
get_cache(:tree, sha) { tree!(sha) }
|
53
|
+
else
|
54
|
+
[]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Public: Fetches the contents of the Git blob at the given SHA.
|
59
|
+
#
|
60
|
+
# sha - A String Git SHA.
|
61
|
+
#
|
62
|
+
# Returns the String content of the blob.
|
63
|
+
def blob(sha)
|
64
|
+
cat_file!(sha)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Public: Looks up the Git commit using the given Git SHA or ref.
|
68
|
+
#
|
69
|
+
# ref - A String Git SHA or ref.
|
70
|
+
#
|
71
|
+
# Returns a Grit::Commit.
|
72
|
+
def commit(ref)
|
73
|
+
if sha?(ref)
|
74
|
+
get_cache(:commit, ref) { commit!(ref) }
|
75
|
+
else
|
76
|
+
if sha = get_cache(:ref, ref)
|
77
|
+
commit(sha)
|
78
|
+
else
|
79
|
+
if cm = commit!(ref)
|
80
|
+
set_cache(:ref, ref, cm.id)
|
81
|
+
set_cache(:commit, cm.id, cm)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Public: Clears all of the cached data that this GitAccess is tracking.
|
88
|
+
#
|
89
|
+
# Returns nothing.
|
90
|
+
def clear
|
91
|
+
@ref_map = {}
|
92
|
+
@tree_map = {}
|
93
|
+
@commit_map = {}
|
94
|
+
end
|
95
|
+
|
96
|
+
# Public: Refreshes just the cached Git reference data. This should
|
97
|
+
# be called after every Gollum update.
|
98
|
+
#
|
99
|
+
# Returns nothing.
|
100
|
+
def refresh
|
101
|
+
@ref_map.clear
|
102
|
+
end
|
103
|
+
|
104
|
+
#########################################################################
|
105
|
+
#
|
106
|
+
# Internal Methods
|
107
|
+
#
|
108
|
+
#########################################################################
|
109
|
+
|
110
|
+
# Gets the String path to the Git repository.
|
111
|
+
attr_reader :path
|
112
|
+
|
113
|
+
# Gets the Grit::Repo instance for the Git repository.
|
114
|
+
attr_reader :repo
|
115
|
+
|
116
|
+
# Gets a Hash cache of refs to commit SHAs.
|
117
|
+
#
|
118
|
+
# {"master" => "abc123", ...}
|
119
|
+
#
|
120
|
+
attr_reader :ref_map
|
121
|
+
|
122
|
+
# Gets a Hash cache of commit SHAs to a recursive tree of blobs.
|
123
|
+
#
|
124
|
+
# {"abc123" => [<BlobEntry>, <BlobEntry>]}
|
125
|
+
#
|
126
|
+
attr_reader :tree_map
|
127
|
+
|
128
|
+
# Gets a Hash cache of commit SHAs to the Grit::Commit instance.
|
129
|
+
#
|
130
|
+
# {"abcd123" => <Grit::Commit>}
|
131
|
+
#
|
132
|
+
attr_reader :commit_map
|
133
|
+
|
134
|
+
# Checks to see if the given String is a 40 character hex SHA.
|
135
|
+
#
|
136
|
+
# str - Possible String SHA.
|
137
|
+
#
|
138
|
+
# Returns true if the String is a SHA, or false.
|
139
|
+
def sha?(str)
|
140
|
+
!!(str =~ /^[0-9a-f]{40}$/)
|
141
|
+
end
|
142
|
+
|
143
|
+
# Looks up the Git SHA for the given Git ref.
|
144
|
+
#
|
145
|
+
# ref - String Git ref.
|
146
|
+
#
|
147
|
+
# Returns a String SHA.
|
148
|
+
def ref_to_sha!(ref)
|
149
|
+
@repo.git.rev_list({:max_count=>1}, ref)
|
150
|
+
rescue Grit::GitRuby::Repository::NoSuchShaFound
|
151
|
+
end
|
152
|
+
|
153
|
+
# Looks up the Git blobs for a given commit.
|
154
|
+
#
|
155
|
+
# sha - String commit SHA.
|
156
|
+
#
|
157
|
+
# Returns an Array of BlobEntry instances.
|
158
|
+
def tree!(sha)
|
159
|
+
tree = @repo.git.native(:ls_tree,
|
160
|
+
{:r => true, :l => true, :z => true}, sha)
|
161
|
+
if tree.respond_to?(:force_encoding)
|
162
|
+
tree.force_encoding("UTF-8")
|
163
|
+
end
|
164
|
+
items = tree.split("\0").inject([]) do |memo, line|
|
165
|
+
memo << parse_tree_line(line)
|
166
|
+
end
|
167
|
+
|
168
|
+
if dir = @page_file_dir
|
169
|
+
regex = /^#{dir}\//
|
170
|
+
items.select { |i| i.path =~ regex }
|
171
|
+
else
|
172
|
+
items
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Reads the content from the Git db at the given SHA.
|
177
|
+
#
|
178
|
+
# sha - The String SHA.
|
179
|
+
#
|
180
|
+
# Returns the String content of the Git object.
|
181
|
+
def cat_file!(sha)
|
182
|
+
@repo.git.cat_file({:p => true}, sha)
|
183
|
+
end
|
184
|
+
|
185
|
+
# Reads a Git commit.
|
186
|
+
#
|
187
|
+
# sha - The string SHA of the Git commit.
|
188
|
+
#
|
189
|
+
# Returns a Grit::Commit.
|
190
|
+
def commit!(sha)
|
191
|
+
@repo.commit(sha)
|
192
|
+
end
|
193
|
+
|
194
|
+
# Attempts to get the given data from a cache. If it doesn't exist, it'll
|
195
|
+
# pass the results of the yielded block to the cache for future accesses.
|
196
|
+
#
|
197
|
+
# name - The cache prefix used in building the full cache key.
|
198
|
+
# key - The unique cache key suffix, usually a String Git SHA.
|
199
|
+
#
|
200
|
+
# Yields a block to pass to the cache.
|
201
|
+
# Returns the cached result.
|
202
|
+
def get_cache(name, key)
|
203
|
+
cache = instance_variable_get("@#{name}_map")
|
204
|
+
value = cache[key]
|
205
|
+
if value.nil? && block_given?
|
206
|
+
set_cache(name, key, value = yield)
|
207
|
+
end
|
208
|
+
value == :_nil ? nil : value
|
209
|
+
end
|
210
|
+
|
211
|
+
# Writes some data to the internal cache.
|
212
|
+
#
|
213
|
+
# name - The cache prefix used in building the full cache key.
|
214
|
+
# key - The unique cache key suffix, usually a String Git SHA.
|
215
|
+
# value - The value to write to the cache.
|
216
|
+
#
|
217
|
+
# Returns nothing.
|
218
|
+
def set_cache(name, key, value)
|
219
|
+
cache = instance_variable_get("@#{name}_map")
|
220
|
+
cache[key] = value || :_nil
|
221
|
+
end
|
222
|
+
|
223
|
+
# Parses a line of output from the `ls-tree` command.
|
224
|
+
#
|
225
|
+
# line - A String line of output:
|
226
|
+
# "100644 blob 839c2291b30495b9a882c17d08254d3c90d8fb53 Home.md"
|
227
|
+
#
|
228
|
+
# Returns an Array of BlobEntry instances.
|
229
|
+
def parse_tree_line(line)
|
230
|
+
mode, type, sha, size, *name = line.split(/\s+/)
|
231
|
+
BlobEntry.new(sha, name.join(' '), size.to_i)
|
232
|
+
end
|
233
|
+
|
234
|
+
# Decode octal sequences (\NNN) in tree path names.
|
235
|
+
#
|
236
|
+
# path - String path name.
|
237
|
+
#
|
238
|
+
# Returns a decoded String.
|
239
|
+
def decode_git_path(path)
|
240
|
+
if path[0] == ?" && path[-1] == ?"
|
241
|
+
path = path[1...-1]
|
242
|
+
path.gsub!(/\\\d{3}/) { |m| m[1..-1].to_i(8).chr }
|
243
|
+
end
|
244
|
+
path.gsub!(/\\[rn"\\]/) { |m| eval(%("#{m.to_s}")) }
|
245
|
+
path
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|