smeagol 0.5.9 → 0.6.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.
- data/.ruby +80 -0
- data/.yardopts +9 -0
- data/HISTORY.md +147 -0
- data/LICENSE.txt +30 -0
- data/README.md +132 -26
- data/bin/smeagol +9 -39
- data/bin/smeagol-init +3 -0
- data/bin/smeagol-preview +4 -0
- data/bin/smeagol-serve +4 -0
- data/bin/smeagol-update +4 -0
- data/bin/smeagold +1 -4
- data/lib/smeagol.rb +77 -6
- data/lib/smeagol/app.rb +121 -75
- data/lib/smeagol/cache.rb +43 -24
- data/lib/smeagol/cli.rb +166 -0
- data/lib/smeagol/config.rb +154 -0
- data/lib/smeagol/console.rb +369 -0
- data/lib/smeagol/controller.rb +275 -0
- data/lib/smeagol/core_ext.rb +12 -0
- data/lib/smeagol/gollum/blob_entry.rb +17 -0
- data/lib/smeagol/gollum/file.rb +44 -0
- data/lib/smeagol/gollum/page.rb +47 -0
- data/lib/smeagol/gollum/wiki.rb +31 -0
- data/lib/smeagol/helpers/rss.rb +96 -0
- data/lib/smeagol/helpers/toc.rb +69 -0
- data/lib/smeagol/public/assets/smeagol/gollum.css +716 -0
- data/lib/smeagol/public/{smeagol → assets/smeagol}/html5.js +0 -0
- data/lib/smeagol/public/{smeagol → assets/smeagol}/pygment.css +0 -0
- data/lib/smeagol/public/assets/smeagol/template.css +631 -0
- data/lib/smeagol/repository.rb +85 -0
- data/lib/smeagol/settings.rb +302 -0
- data/lib/smeagol/templates/layouts/page.mustache +19 -0
- data/lib/smeagol/templates/layouts/versions.mustache +16 -0
- data/lib/smeagol/templates/partials/footer.mustache +17 -0
- data/lib/smeagol/templates/partials/header.mustache +47 -0
- data/lib/smeagol/templates/settings.yml +64 -0
- data/lib/smeagol/version.rb +1 -1
- data/lib/smeagol/views/base.rb +188 -27
- data/lib/smeagol/views/form.rb +56 -0
- data/lib/smeagol/views/page.rb +126 -25
- data/lib/smeagol/views/post.rb +51 -0
- data/lib/smeagol/views/versions.rb +20 -6
- data/lib/smeagol/wiki.rb +25 -45
- data/test/helper.rb +72 -8
- data/test/test_app.rb +57 -0
- data/test/test_cache.rb +10 -11
- data/test/test_init.rb +27 -0
- data/test/test_update.rb +20 -0
- data/test/test_wiki.rb +13 -10
- metadata +142 -216
- data/bin/smeagol-static +0 -115
- data/lib/file.rb +0 -10
- data/lib/smeagol/hash.rb +0 -13
- data/lib/smeagol/option_parser.rb +0 -138
- data/lib/smeagol/public/smeagol/main.css +0 -234
- data/lib/smeagol/templates/page.mustache +0 -58
- data/lib/smeagol/templates/versions.mustache +0 -50
- data/test/test_file.rb +0 -12
- data/test/test_hash.rb +0 -18
data/bin/smeagol-static
DELETED
@@ -1,115 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'rubygems'
|
4
|
-
require 'mustache'
|
5
|
-
require 'optparse'
|
6
|
-
require 'smeagol'
|
7
|
-
|
8
|
-
class Static
|
9
|
-
def initialize(wiki)
|
10
|
-
@wiki = wiki
|
11
|
-
@directory = []
|
12
|
-
end
|
13
|
-
|
14
|
-
def template
|
15
|
-
if File.exists?("#{@wiki.path}/page.mustache")
|
16
|
-
IO.read("#{@wiki.path}/page.mustache")
|
17
|
-
else
|
18
|
-
IO.read(File.join(File.dirname(__FILE__), "../lib/smeagol/templates/page.mustache"))
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def current_directory
|
23
|
-
@directory.last
|
24
|
-
end
|
25
|
-
|
26
|
-
def directory_pop
|
27
|
-
@directory.pop()
|
28
|
-
end
|
29
|
-
|
30
|
-
def directory_push(dir)
|
31
|
-
if @directory.empty?
|
32
|
-
@directory << dir
|
33
|
-
else
|
34
|
-
@directory << "#{current_directory}/#{dir}"
|
35
|
-
end
|
36
|
-
|
37
|
-
if not File.directory?(current_directory)
|
38
|
-
Dir::mkdir(current_directory)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def build_tree(tree)
|
43
|
-
tree.contents.each do |item|
|
44
|
-
if item.class == Grit::Tree
|
45
|
-
directory_push(item.name)
|
46
|
-
build_tree(item)
|
47
|
-
directory_pop()
|
48
|
-
else
|
49
|
-
build_blob(item)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def build_blob(blob)
|
55
|
-
if name = @wiki.page_class.valid_page_name?(blob.name)
|
56
|
-
page = @wiki.page(name)
|
57
|
-
|
58
|
-
if name != 'Home'
|
59
|
-
directory_push(name)
|
60
|
-
end
|
61
|
-
|
62
|
-
File.open("#{current_directory}/index.html", 'w') do |f|
|
63
|
-
f.write(Mustache.render(template, Smeagol::Views::Page.new(page)))
|
64
|
-
end
|
65
|
-
|
66
|
-
if name != 'Home'
|
67
|
-
directory_pop
|
68
|
-
end
|
69
|
-
else
|
70
|
-
File.open("#{current_directory}/#{blob.name}", 'w') do |f|
|
71
|
-
f.write(blob.data)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def build(directory)
|
77
|
-
directory_push(directory)
|
78
|
-
build_tree(@wiki.repo.tree)
|
79
|
-
directory_pop
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
options = {}
|
84
|
-
optparse = OptionParser.new do |opts|
|
85
|
-
opts.banner = "usage: smeagol-static [options] [path]"
|
86
|
-
|
87
|
-
opts.on('-h', '--help', 'Displays this usage screen') do
|
88
|
-
puts optparse
|
89
|
-
exit
|
90
|
-
end
|
91
|
-
|
92
|
-
opts.on('-b', '--build DIRECTORY') do |dir|
|
93
|
-
options[:build_dir] = dir
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
begin
|
98
|
-
optparse.parse!
|
99
|
-
rescue OptionParser::InvalidOption
|
100
|
-
puts optparse
|
101
|
-
exit 1
|
102
|
-
end
|
103
|
-
|
104
|
-
if ARGV.first
|
105
|
-
options[:repo] = ARGV.first
|
106
|
-
else
|
107
|
-
options[:repo] = Dir.pwd
|
108
|
-
end
|
109
|
-
|
110
|
-
if not options.key?(:build_dir)
|
111
|
-
options[:build_dir] = options[:repo] + "/build"
|
112
|
-
end
|
113
|
-
|
114
|
-
static = Static.new(Smeagol::Wiki.new(options[:repo]))
|
115
|
-
static.build(options[:build_dir])
|
data/lib/file.rb
DELETED
data/lib/smeagol/hash.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
class Hash
|
2
|
-
# Recursively converts a Hash object to an OpenStruct object.
|
3
|
-
#
|
4
|
-
# Returns a copy of the hash as an OpenStruct.
|
5
|
-
def to_ostruct()
|
6
|
-
struct = OpenStruct.new(self.clone())
|
7
|
-
each do |k, v|
|
8
|
-
struct.__send__("#{k}=", v.to_ostruct()) if v.is_a?(Hash)
|
9
|
-
struct.__send__(k).map! {|x| x.is_a?(Hash) ? x.to_ostruct() : x} if v.is_a?(Array)
|
10
|
-
end
|
11
|
-
return struct
|
12
|
-
end
|
13
|
-
end
|
@@ -1,138 +0,0 @@
|
|
1
|
-
module Smeagol
|
2
|
-
class OptionParser
|
3
|
-
# Parses the command line options.
|
4
|
-
#
|
5
|
-
# args - The arguments to parse. Typically use `ARGV`.
|
6
|
-
#
|
7
|
-
# Returns an OpenStruct of the options.
|
8
|
-
def self.parse(args)
|
9
|
-
# Set parse options
|
10
|
-
secret = nil
|
11
|
-
options = {}
|
12
|
-
parser = ::OptionParser.new do |parser|
|
13
|
-
parser.banner = 'usage: smeagol [OPTIONS] [PATH]\n\n'
|
14
|
-
|
15
|
-
parser.on('--port [PORT]', 'Bind port (default 4567).') do |port|
|
16
|
-
options['port'] = port.to_i
|
17
|
-
end
|
18
|
-
|
19
|
-
parser.on('--git [GIT]', 'Path to Git binary.') do |path|
|
20
|
-
options['git'] = path
|
21
|
-
end
|
22
|
-
|
23
|
-
parser.on('-c', '--config [PATH]', 'Loads the config file. (default /etc/smeagol/config.yml)') do |path|
|
24
|
-
puts "Cannot find configuration file: #{path}" unless File.exists?(path)
|
25
|
-
puts "Cannot read configuration file: #{path}" unless File.readable?(path)
|
26
|
-
options['config_path'] = path
|
27
|
-
end
|
28
|
-
|
29
|
-
parser.on('--auto-update', 'Updates the repository on a daily basis.') do |flag|
|
30
|
-
options['auto_update'] = flag
|
31
|
-
end
|
32
|
-
|
33
|
-
parser.on('--[no-]cache', 'Enables page caching.') do |flag|
|
34
|
-
options['cache_enabled'] = flag
|
35
|
-
end
|
36
|
-
|
37
|
-
parser.on('--secret [KEY]', 'Specifies the secret key used to update.') do |str|
|
38
|
-
secret = str
|
39
|
-
end
|
40
|
-
|
41
|
-
parser.on('-v', '--version', 'Display current version.') do
|
42
|
-
puts "Smeagol #{Smeagol::VERSION}"
|
43
|
-
exit 0
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# Read command line options into `options` hash
|
48
|
-
begin
|
49
|
-
parser.parse!
|
50
|
-
rescue ::OptionParser::InvalidOption
|
51
|
-
puts "smeagol: #{$!.message}"
|
52
|
-
puts "smeagol: try 'smeagol --help' for more information"
|
53
|
-
exit
|
54
|
-
end
|
55
|
-
|
56
|
-
# Load config
|
57
|
-
config_path = options['config_path'] || '/etc/smeagol/config.yml'
|
58
|
-
config = load_config(config_path)
|
59
|
-
opts = default_options.merge(config).merge(options)
|
60
|
-
opts = opts.to_ostruct()
|
61
|
-
|
62
|
-
# Attempt to find the git binary
|
63
|
-
update_git_path(opts)
|
64
|
-
|
65
|
-
# Append repositories from the command line.
|
66
|
-
opts.repositories ||= []
|
67
|
-
if !args.first.nil?
|
68
|
-
opts.repositories.unshift({:path => args.first}.to_ostruct)
|
69
|
-
end
|
70
|
-
|
71
|
-
# Set repository to present working directory if no paths specified.
|
72
|
-
if opts.repositories.empty?
|
73
|
-
opts.repositories = [{:path => Dir.pwd}.to_ostruct]
|
74
|
-
end
|
75
|
-
|
76
|
-
# Set secret on default repository if passed in.
|
77
|
-
opts.repositories.first.secret = secret unless secret.nil?
|
78
|
-
|
79
|
-
# Merge all options
|
80
|
-
return opts
|
81
|
-
end
|
82
|
-
|
83
|
-
|
84
|
-
###########################################################################
|
85
|
-
#
|
86
|
-
# Private Methods
|
87
|
-
#
|
88
|
-
###########################################################################
|
89
|
-
|
90
|
-
private
|
91
|
-
|
92
|
-
# The default options for Smeagol.
|
93
|
-
def self.default_options
|
94
|
-
options = Hash.new
|
95
|
-
options['port'] = 4567
|
96
|
-
options['auto_update'] = false
|
97
|
-
options['cache_enabled'] = true
|
98
|
-
options
|
99
|
-
end
|
100
|
-
|
101
|
-
# Loads a configuration file.
|
102
|
-
#
|
103
|
-
# Returns a hash of options from the config file.
|
104
|
-
def self.load_config(path)
|
105
|
-
config = {}
|
106
|
-
|
107
|
-
if File.exists?(path)
|
108
|
-
# Notify the user if the config file exists but is not readable.
|
109
|
-
if !File.readable?(path)
|
110
|
-
puts "Config file not readable: #{path}"
|
111
|
-
exit
|
112
|
-
end
|
113
|
-
|
114
|
-
config = YAML.load(IO.read(path))
|
115
|
-
end
|
116
|
-
|
117
|
-
return config
|
118
|
-
end
|
119
|
-
|
120
|
-
# Locates the git binary in common places in the file system.
|
121
|
-
def self.update_git_path(options)
|
122
|
-
if options.git.nil?
|
123
|
-
['/usr/bin', '/usr/sbin', '/usr/local/bin', '/opt/local/bin'].each do |path|
|
124
|
-
file = "#{path}/git"
|
125
|
-
options.git = file if File.executable?(file)
|
126
|
-
break if options.git
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
# Alert user that updates are unavailable if git is not found
|
131
|
-
if options.git.nil? || !File.executable?(options.git)
|
132
|
-
puts "warning: git executable could not be found."
|
133
|
-
else
|
134
|
-
puts "git found: #{options.git}"
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
@@ -1,234 +0,0 @@
|
|
1
|
-
/* Reset from: http://meyerweb.com/eric/tools/css/reset/ */
|
2
|
-
html, body, div, span, applet, object, iframe,
|
3
|
-
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
4
|
-
a, abbr, acronym, address, big, cite, code,
|
5
|
-
del, dfn, em, font, img, ins, kbd, q, s, samp,
|
6
|
-
small, strike, strong, sub, sup, tt, var,
|
7
|
-
b, u, i, center,
|
8
|
-
dl, dt, dd, ol, ul, li,
|
9
|
-
fieldset, form, label, legend,
|
10
|
-
table, caption, tbody, tfoot, thead, tr, th, td {
|
11
|
-
margin: 0;
|
12
|
-
padding: 0;
|
13
|
-
border: 0;
|
14
|
-
outline: 0;
|
15
|
-
font-size: 100%;
|
16
|
-
vertical-align: baseline;
|
17
|
-
background: transparent;
|
18
|
-
}
|
19
|
-
body {
|
20
|
-
line-height: 1;
|
21
|
-
}
|
22
|
-
ol, ul {
|
23
|
-
list-style: none;
|
24
|
-
}
|
25
|
-
blockquote, q {
|
26
|
-
quotes: none;
|
27
|
-
}
|
28
|
-
blockquote:before, blockquote:after,
|
29
|
-
q:before, q:after {
|
30
|
-
content: '';
|
31
|
-
content: none;
|
32
|
-
}
|
33
|
-
|
34
|
-
:focus {
|
35
|
-
outline: 0;
|
36
|
-
}
|
37
|
-
|
38
|
-
ins {
|
39
|
-
text-decoration: none;
|
40
|
-
}
|
41
|
-
del {
|
42
|
-
text-decoration: line-through;
|
43
|
-
}
|
44
|
-
|
45
|
-
table {
|
46
|
-
border-collapse: collapse;
|
47
|
-
border-spacing: 0;
|
48
|
-
}
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
/* Main styles */
|
53
|
-
body {
|
54
|
-
font: normal normal normal 13.34px/normal helvetica, arial, sans-serif;
|
55
|
-
font-size: 14px;
|
56
|
-
line-height: 1.4em;
|
57
|
-
}
|
58
|
-
|
59
|
-
a {
|
60
|
-
color: #4183C4;
|
61
|
-
text-decoration: none;
|
62
|
-
}
|
63
|
-
|
64
|
-
a:hover {
|
65
|
-
text-decoration: underline;
|
66
|
-
}
|
67
|
-
|
68
|
-
|
69
|
-
header {
|
70
|
-
display: block;
|
71
|
-
}
|
72
|
-
|
73
|
-
footer {
|
74
|
-
display: block;
|
75
|
-
border-top: 2px solid #ccc;
|
76
|
-
padding-top: 1px;
|
77
|
-
margin-top: 2.5em;
|
78
|
-
margin-bottom: 2em;
|
79
|
-
}
|
80
|
-
|
81
|
-
nav {
|
82
|
-
display: block;
|
83
|
-
border-top: 1px solid #ccc;
|
84
|
-
border-bottom: 1px solid #ccc;
|
85
|
-
margin-bottom: 1.5em;
|
86
|
-
}
|
87
|
-
|
88
|
-
nav ul {
|
89
|
-
padding: 2px 2px 2px 2px;
|
90
|
-
margin: 3px 0px 0px;
|
91
|
-
white-space: nowrap;
|
92
|
-
}
|
93
|
-
|
94
|
-
nav ul li {
|
95
|
-
display: inline;
|
96
|
-
list-style-type: none;
|
97
|
-
padding: 0px 35px 0px 0px;
|
98
|
-
}
|
99
|
-
|
100
|
-
nav ul li a {
|
101
|
-
color: #333;
|
102
|
-
font-weight: bold;
|
103
|
-
text-decoration: none;
|
104
|
-
}
|
105
|
-
|
106
|
-
nav ul li a:hover {
|
107
|
-
color: black;
|
108
|
-
}
|
109
|
-
|
110
|
-
|
111
|
-
.tagline {
|
112
|
-
font-style: italic;
|
113
|
-
}
|
114
|
-
|
115
|
-
#container {
|
116
|
-
margin-left: auto;
|
117
|
-
margin-right: auto;
|
118
|
-
width: 650px;
|
119
|
-
}
|
120
|
-
|
121
|
-
h1 {
|
122
|
-
font-size: 250%;
|
123
|
-
margin-top: 1em;
|
124
|
-
margin-bottom: 0.3em;
|
125
|
-
}
|
126
|
-
|
127
|
-
article h1 {
|
128
|
-
font-size: 150%;
|
129
|
-
margin-bottom: 0.7em;
|
130
|
-
}
|
131
|
-
|
132
|
-
#content {
|
133
|
-
color: #333;
|
134
|
-
}
|
135
|
-
|
136
|
-
#content h1 {
|
137
|
-
color: black;
|
138
|
-
border-top: 4px solid #aaa;
|
139
|
-
margin-top: 1.5em;
|
140
|
-
padding-top: 0.5em;
|
141
|
-
}
|
142
|
-
|
143
|
-
#content h2 {
|
144
|
-
font-size: 135%;
|
145
|
-
color: black;
|
146
|
-
border-top: 4px solid #e0e0e0;
|
147
|
-
margin-top: 1.5em;
|
148
|
-
padding-top: 0.5em;
|
149
|
-
}
|
150
|
-
|
151
|
-
#content h3 {
|
152
|
-
font-size: 110%;
|
153
|
-
margin-top:1.25em;
|
154
|
-
margin-bottom:0.4em;
|
155
|
-
font-size: 1.17em;
|
156
|
-
}
|
157
|
-
|
158
|
-
#content p {
|
159
|
-
line-height: 1.5em;
|
160
|
-
margin: 0.4em 0em 1em 0em;
|
161
|
-
}
|
162
|
-
|
163
|
-
#content ol {
|
164
|
-
padding: 0px;
|
165
|
-
margin: 1em 0px 1em 2em;
|
166
|
-
display: block;
|
167
|
-
list-style-type: decimal;
|
168
|
-
}
|
169
|
-
|
170
|
-
#content ul {
|
171
|
-
padding: 0px;
|
172
|
-
margin: 1em 0px 1em 2em;
|
173
|
-
display: block;
|
174
|
-
list-style-type: disc;
|
175
|
-
}
|
176
|
-
|
177
|
-
#content li {
|
178
|
-
margin-bottom: 0.5em;
|
179
|
-
margin-top: 0.5em;
|
180
|
-
}
|
181
|
-
|
182
|
-
pre {
|
183
|
-
line-height: 1.5em;
|
184
|
-
margin: 1em 0px;
|
185
|
-
overflow: auto;
|
186
|
-
padding: 0.5em;
|
187
|
-
}
|
188
|
-
|
189
|
-
code {
|
190
|
-
padding: 0px 0.2em;
|
191
|
-
}
|
192
|
-
|
193
|
-
pre, code {
|
194
|
-
background-color: ghostWhite;
|
195
|
-
border: 1px solid #ddd;
|
196
|
-
color: #444;
|
197
|
-
font-size: 12px;
|
198
|
-
font: normal normal normal 12px/normal Monaco, 'Courier New', monospace;
|
199
|
-
}
|
200
|
-
|
201
|
-
pre > code {
|
202
|
-
border:none !important;
|
203
|
-
}
|
204
|
-
|
205
|
-
small {
|
206
|
-
font-size: 80%;
|
207
|
-
}
|
208
|
-
|
209
|
-
span.frame{
|
210
|
-
display:block;
|
211
|
-
overflow:hidden;
|
212
|
-
}
|
213
|
-
|
214
|
-
span.frame > span{
|
215
|
-
border: 1px solid #ddd;
|
216
|
-
display: block;
|
217
|
-
overflow: hidden;
|
218
|
-
float: left;
|
219
|
-
margin: 13px 0 0;
|
220
|
-
padding: 7px;
|
221
|
-
width:auto;
|
222
|
-
}
|
223
|
-
|
224
|
-
span.frame span img{
|
225
|
-
display: block;
|
226
|
-
float: left;
|
227
|
-
}
|
228
|
-
|
229
|
-
span.frame span span{
|
230
|
-
clear: both;
|
231
|
-
color: #333;
|
232
|
-
display: block;
|
233
|
-
padding:5px 0 0;
|
234
|
-
}
|