Compare commits
87 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 996f81d63d | |||
| 16ef859073 | |||
| e7b1265873 | |||
| c0f8c897e7 | |||
| 33aad801bd | |||
| dd7dddddcf | |||
| 251d5c8201 | |||
| 4dbe3ea844 | |||
| cc929bbc56 | |||
| 5e59e39d67 | |||
| 05a7b4c06c | |||
| 7924db8e01 | |||
| 4b313944fe | |||
| 9786f5f347 | |||
| 42985dc5c1 | |||
| ee6b71ff80 | |||
| cdf75d20ef | |||
| 1e2932fd21 | |||
| 4bb7d53854 | |||
| e37a8b9da4 | |||
| 48bfe954d1 | |||
| 9cc8790d4f | |||
| d51f42e647 | |||
| 430436ce8d | |||
| e774ceaf1f | |||
| 42bd6c221a | |||
| 50e9a42503 | |||
| 5fcb5d971a | |||
| e9239050e0 | |||
| 50c207ad91 | |||
| 7c70174725 | |||
| e0d234c255 | |||
| bf37f44970 | |||
| 847e6c00a4 | |||
| 6de9ddfd3f | |||
| 1f8a67598a | |||
| 515f8610c4 | |||
| ba18cbebe8 | |||
| 646c8e21b2 | |||
| 6dab4f7fe6 | |||
| 7e2b1fdbc6 | |||
| 6f077702e1 | |||
| f4c4b2e49c | |||
| db1ccc4525 | |||
| dddb73672a | |||
| 94f05b0796 | |||
| 6d3b40c1d4 | |||
| 45eb364a6d | |||
| 959f02b50e | |||
| 49d88a0370 | |||
| ed41152228 | |||
| 294847ed99 | |||
| 8301428974 | |||
| 0500c7e10c | |||
| 3eeed9ba1e | |||
| 292f6ec8dc | |||
| 068a902a00 | |||
| d606511fdf | |||
| cc3d9529cc | |||
| 74ca65b045 | |||
| 05283347b0 | |||
| 99995f7364 | |||
| 8c625419b8 | |||
| d1003f5331 | |||
| 4905ce99da | |||
| 48b143c6ed | |||
| dae2e0c79c | |||
| 9b32d3bfb1 | |||
| b1fc173a3f | |||
| 6a53e3d037 | |||
| 15879a5a88 | |||
| c6e2acbf62 | |||
| 28a29f49f2 | |||
| acdb04ba4e | |||
| dd30a7bdc2 | |||
| c7e172f5ca | |||
| c69a5f80dd | |||
| ee04dd84aa | |||
| 763387979a | |||
| 4e3b4e23da | |||
| 8b0c971552 | |||
| f4069f1dfb | |||
| 3d730295b3 | |||
| edcfdfa402 | |||
| 45446f3481 | |||
| 2a905cedc9 | |||
| f159c54dc8 |
+34
@@ -1,3 +1,37 @@
|
||||
# 1.1.0 / 2010-10-28
|
||||
|
||||
* Major Enhancements
|
||||
* Optimize page write/update/delete to use Grit::Index::read_tree instead
|
||||
of manually recreating entire index contents.
|
||||
* Added --irb option for the gollum command.
|
||||
* Update working dir (if present) when edited via the API (#6)
|
||||
* Add basic `git grep` based search for repos.
|
||||
* Minor Enhancements
|
||||
* Support a `:gollum_path` Sinatra setting for `Precious::App`
|
||||
* Add Wiki#size to efficiently count pages without loading them.
|
||||
* Add the correct content type when serving files from the frontend.
|
||||
* Add --host option and default it to 127.0.0.1.
|
||||
* Allow anchors in page links, such as `[[Abc#header]]`.
|
||||
* All pages retrieved with a SHA add `rel="nofollow"` to all
|
||||
page links.
|
||||
* Bug Fixes
|
||||
* Increase minimum Sanitize version requirement to 1.1.0.
|
||||
1.0.x versions of Sanitize require Hpricot instead of Nokogiri
|
||||
and have bugs that may allow non-whitelisted HTML to sneak
|
||||
through.
|
||||
* Introduce Ruby 1.9 compatibility fixes.
|
||||
* Commit hashes are normalized so that missing author data is replaced with
|
||||
anonymous info.
|
||||
* Prevent `Gollum::Wiki#write_page` from clobbering existing pages.
|
||||
* Handle duplicate page errors in frontend.
|
||||
* Fix bugs trying to retrieve pages with invalid names.
|
||||
* CGI escape page names in links and redirects.
|
||||
|
||||
# 1.0.1 / 2010-08-12
|
||||
|
||||
* Bug Fixes
|
||||
* Force Grit dep to 2.1 or higher.
|
||||
|
||||
# 1.0.0 / 2010-08-12
|
||||
|
||||
* Open Source Birthday!
|
||||
@@ -63,7 +63,7 @@ choose. Special footers can be created in `footer files`. Other content
|
||||
## PAGE FILES
|
||||
|
||||
Page files may be written in any format supported by
|
||||
[GitHub-Markup](http://github.com/defunkt/github-markup) (except roff). The
|
||||
[GitHub-Markup](http://github.com/github/markup) (except roff). The
|
||||
current list of formats and allowed extensions is:
|
||||
|
||||
* ASCIIDoc: .asciidoc
|
||||
@@ -326,7 +326,7 @@ Initialize the Gollum::Repo object:
|
||||
wiki = Gollum::Wiki.new("my-gollum-repo.git")
|
||||
# => <Gollum::Wiki>
|
||||
|
||||
By default, internal wiki links are all absolute from the root. To specify a different base path, you can send specify the `:base_path` option:
|
||||
By default, internal wiki links are all absolute from the root. To specify a different base path, you can specify the `:base_path` option:
|
||||
|
||||
wiki = Gollum::Wiki.new("my-gollum-repo.git", :base_path => "/wiki")
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ task :default => :test
|
||||
|
||||
require 'rake/testtask'
|
||||
Rake::TestTask.new(:test) do |test|
|
||||
test.libs << 'lib' << 'test'
|
||||
test.libs << 'lib' << 'test' << '.'
|
||||
test.pattern = 'test/**/test_*.rb'
|
||||
test.verbose = true
|
||||
end
|
||||
@@ -95,7 +95,7 @@ task :release => :build do
|
||||
sh "git commit --allow-empty -a -m 'Release #{version}'"
|
||||
sh "git tag v#{version}"
|
||||
sh "git push origin master"
|
||||
sh "git push v#{version}"
|
||||
sh "git push origin v#{version}"
|
||||
sh "gem push pkg/#{name}-#{version}.gem"
|
||||
end
|
||||
|
||||
@@ -143,4 +143,4 @@ task :validate do
|
||||
puts "A `VERSION` file at root level violates Gem best practices."
|
||||
exit!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+69
-7
@@ -8,18 +8,17 @@ Gollum is a multi-format Wiki Engine/API/Frontend.
|
||||
Basic Command Line Usage:
|
||||
gollum [OPTIONS] [PATH]
|
||||
|
||||
PATH The path to the Gollum repository.
|
||||
PATH The path to the Gollum repository (default .).
|
||||
|
||||
Options:
|
||||
HELP
|
||||
|
||||
require 'optparse'
|
||||
|
||||
require 'rubygems'
|
||||
require 'gollum/frontend/app'
|
||||
require 'gollum'
|
||||
|
||||
exec = {}
|
||||
options = {}
|
||||
options = { 'port' => 4567, 'bind' => '127.0.0.1' }
|
||||
opts = OptionParser.new do |opts|
|
||||
opts.banner = help
|
||||
|
||||
@@ -27,15 +26,78 @@ opts = OptionParser.new do |opts|
|
||||
options['port'] = port.to_i
|
||||
end
|
||||
|
||||
opts.on("--host [HOST]", "Hostname or IP address to listen on (default 0.0.0.0).") do |host|
|
||||
options['bind'] = host
|
||||
end
|
||||
|
||||
opts.on("--version", "Display current version.") do
|
||||
puts "Gollum " + Gollum::VERSION
|
||||
exit 0
|
||||
end
|
||||
|
||||
opts.on("--irb", "Start an irb process with gollum loaded for the current wiki.") do
|
||||
options['irb'] = true
|
||||
end
|
||||
end
|
||||
|
||||
# Read command line options into `options` hash
|
||||
opts.parse!
|
||||
begin
|
||||
opts.parse!
|
||||
rescue OptionParser::InvalidOption
|
||||
puts "gollum: #{$!.message}"
|
||||
puts "gollum: try 'gollum --help' for more information"
|
||||
exit
|
||||
end
|
||||
|
||||
$path = ARGV[0] || Dir.pwd
|
||||
gollum_path = ARGV[0] || Dir.pwd
|
||||
|
||||
Precious::App.run!(options)
|
||||
if options['irb']
|
||||
require 'irb'
|
||||
# http://jameskilton.com/2009/04/02/embedding-irb-into-your-ruby-application/
|
||||
module IRB # :nodoc:
|
||||
def self.start_session(binding)
|
||||
unless @__initialized
|
||||
args = ARGV
|
||||
ARGV.replace(ARGV.dup)
|
||||
IRB.setup(nil)
|
||||
ARGV.replace(args)
|
||||
@__initialized = true
|
||||
end
|
||||
|
||||
ws = WorkSpace.new(binding)
|
||||
irb = Irb.new(ws)
|
||||
|
||||
@CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
|
||||
@CONF[:MAIN_CONTEXT] = irb.context
|
||||
|
||||
catch(:IRB_EXIT) do
|
||||
irb.eval_input
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
begin
|
||||
wiki = Gollum::Wiki.new(gollum_path)
|
||||
if !wiki.exist? then raise Grit::InvalidGitRepositoryError end
|
||||
puts "Loaded Gollum wiki at #{File.expand_path(gollum_path).inspect}."
|
||||
puts
|
||||
puts %( page = wiki.page('page-name'))
|
||||
puts %( # => <Gollum::Page>)
|
||||
puts
|
||||
puts %( page.raw_data)
|
||||
puts %( # => "# My wiki page")
|
||||
puts
|
||||
puts %( page.formatted_data)
|
||||
puts %( # => "<h1>My wiki page</h1>")
|
||||
puts
|
||||
puts "Check out the Gollum README for more."
|
||||
IRB.start_session(binding)
|
||||
rescue Grit::InvalidGitRepositoryError, Grit::NoSuchPathError
|
||||
puts "Invalid Gollum wiki at #{File.expand_path(gollum_path).inspect}"
|
||||
exit 0
|
||||
end
|
||||
else
|
||||
require 'gollum/frontend/app'
|
||||
Precious::App.set(:gollum_path, gollum_path)
|
||||
Precious::App.run!(options)
|
||||
end
|
||||
|
||||
+14
-6
@@ -4,8 +4,8 @@ Gem::Specification.new do |s|
|
||||
s.rubygems_version = '1.3.5'
|
||||
|
||||
s.name = 'gollum'
|
||||
s.version = '1.0.0'
|
||||
s.date = '2010-08-12'
|
||||
s.version = '1.1.0'
|
||||
s.date = '2010-10-28'
|
||||
s.rubyforge_project = 'gollum'
|
||||
|
||||
s.summary = "A simple, Git-powered wiki."
|
||||
@@ -23,17 +23,19 @@ Gem::Specification.new do |s|
|
||||
s.rdoc_options = ["--charset=UTF-8"]
|
||||
s.extra_rdoc_files = %w[README.md LICENSE]
|
||||
|
||||
s.add_dependency('grit', "~> 2.0")
|
||||
s.add_dependency('grit', "~> 2.3")
|
||||
s.add_dependency('github-markup', [">= 0.4.0", "< 1.0.0"])
|
||||
s.add_dependency('albino', "~> 1.0")
|
||||
s.add_dependency('sinatra', "~> 1.0")
|
||||
s.add_dependency('mustache', [">= 0.11.2", "< 1.0.0"])
|
||||
s.add_dependency('sanitize', "~> 1.0")
|
||||
s.add_dependency('sanitize', "~> 1.1")
|
||||
s.add_dependency('nokogiri', "~> 1.4")
|
||||
|
||||
s.add_development_dependency('shoulda')
|
||||
s.add_development_dependency('RedCloth')
|
||||
s.add_development_dependency('mocha')
|
||||
s.add_development_dependency('org-ruby')
|
||||
s.add_development_dependency('rdiscount')
|
||||
s.add_development_dependency('shoulda')
|
||||
|
||||
# = MANIFEST =
|
||||
s.files = %w[
|
||||
@@ -46,6 +48,7 @@ Gem::Specification.new do |s|
|
||||
gollum.gemspec
|
||||
lib/gollum.rb
|
||||
lib/gollum/albino.rb
|
||||
lib/gollum/blob_entry.rb
|
||||
lib/gollum/file.rb
|
||||
lib/gollum/frontend/app.rb
|
||||
lib/gollum/frontend/public/css/editbar.css
|
||||
@@ -443,19 +446,24 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/frontend/templates/create.mustache
|
||||
lib/gollum/frontend/templates/edit.mustache
|
||||
lib/gollum/frontend/templates/editbar.mustache
|
||||
lib/gollum/frontend/templates/error.mustache
|
||||
lib/gollum/frontend/templates/history.mustache
|
||||
lib/gollum/frontend/templates/layout.mustache
|
||||
lib/gollum/frontend/templates/page.mustache
|
||||
lib/gollum/frontend/templates/search.mustache
|
||||
lib/gollum/frontend/views/compare.rb
|
||||
lib/gollum/frontend/views/create.rb
|
||||
lib/gollum/frontend/views/edit.rb
|
||||
lib/gollum/frontend/views/editable.rb
|
||||
lib/gollum/frontend/views/error.rb
|
||||
lib/gollum/frontend/views/history.rb
|
||||
lib/gollum/frontend/views/layout.rb
|
||||
lib/gollum/frontend/views/page.rb
|
||||
lib/gollum/frontend/views/search.rb
|
||||
lib/gollum/markup.rb
|
||||
lib/gollum/page.rb
|
||||
lib/gollum/pagination.rb
|
||||
lib/gollum/ruby1.8.rb
|
||||
lib/gollum/wiki.rb
|
||||
templates/formatting.html
|
||||
test/examples/lotr.git/HEAD
|
||||
@@ -503,4 +511,4 @@ Gem::Specification.new do |s|
|
||||
# = MANIFEST =
|
||||
|
||||
s.test_files = s.files.select { |path| path =~ /^test\/test_.*\.rb/ }
|
||||
end
|
||||
end
|
||||
|
||||
+25
-1
@@ -1,13 +1,18 @@
|
||||
# stdlib
|
||||
require 'digest/md5'
|
||||
require 'ostruct'
|
||||
|
||||
# external
|
||||
require 'grit'
|
||||
require 'github/markup'
|
||||
require 'sanitize'
|
||||
|
||||
# ruby 1.8 compatibility
|
||||
require 'gollum/ruby1.8'
|
||||
|
||||
# internal
|
||||
require 'gollum/pagination'
|
||||
require 'gollum/blob_entry'
|
||||
require 'gollum/wiki'
|
||||
require 'gollum/page'
|
||||
require 'gollum/file'
|
||||
@@ -15,7 +20,7 @@ require 'gollum/markup'
|
||||
require 'gollum/albino'
|
||||
|
||||
module Gollum
|
||||
VERSION = '1.0.0'
|
||||
VERSION = '1.1.0'
|
||||
|
||||
SANITIZATION_OPTIONS = {
|
||||
:elements => [
|
||||
@@ -54,5 +59,24 @@ module Gollum
|
||||
'img' => {'href' => ['http', 'https', :relative]}
|
||||
}
|
||||
}
|
||||
HISTORY_SANITIZATION_OPTIONS = SANITIZATION_OPTIONS.merge(
|
||||
:add_attributes => {
|
||||
'a' => {'rel' => 'nofollow'}
|
||||
}
|
||||
)
|
||||
|
||||
class Error < StandardError; end
|
||||
class DuplicatePageError < Error
|
||||
attr_accessor :dir
|
||||
attr_accessor :existing_path
|
||||
attr_accessor :attempted_path
|
||||
|
||||
def initialize(dir, existing, attempted, message = nil)
|
||||
@dir = dir
|
||||
@existing_path = existing
|
||||
@attempted_path = attempted
|
||||
super(message || "Cannot write #{@dir}/#{@attempted_path}, found #{@dir}/#{@existing_path}.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
module Gollum
|
||||
class BlobEntry
|
||||
# Gets the String SHA for this blob.
|
||||
attr_reader :sha
|
||||
|
||||
# Gets the String full path for this blob.
|
||||
attr_reader :path
|
||||
|
||||
def initialize(sha, path)
|
||||
@sha = sha
|
||||
@path = path
|
||||
@dir = @name = @blob = nil
|
||||
end
|
||||
|
||||
# Gets the normalized directory path for this blob.
|
||||
def dir
|
||||
@dir ||= self.class.normalize_dir(::File.dirname(@path))
|
||||
end
|
||||
|
||||
# Gets the String file base name for this blob.
|
||||
def name
|
||||
@name ||= ::File.basename(@path)
|
||||
end
|
||||
|
||||
# Gets a Grit::Blob instance for this blob.
|
||||
#
|
||||
# repo - Grit::Repo instance for the Grit::Blob.
|
||||
#
|
||||
# Returns an unbaked Grit::Blob instance.
|
||||
def blob(repo)
|
||||
@blob ||= Grit::Blob.create(repo, :id => @sha, :name => @name)
|
||||
end
|
||||
|
||||
# Gets a Page instance for this blob.
|
||||
#
|
||||
# wiki - Gollum::Wiki instance for the Gollum::Page
|
||||
#
|
||||
# Returns a Gollum::Page instance.
|
||||
def page(wiki, commit)
|
||||
blob = self.blob(wiki.repo)
|
||||
page = wiki.page_class.new(wiki).populate(blob, self.dir)
|
||||
page.version = commit
|
||||
page
|
||||
end
|
||||
|
||||
def inspect
|
||||
%(#<Gollum::BlobEntry #{@sha} #{@path}>)
|
||||
end
|
||||
|
||||
# Normalizes a given directory name for searching through tree paths.
|
||||
# Ensures that a directory begins with a slash, or
|
||||
#
|
||||
# normalize_dir("") # => ""
|
||||
# normalize_dir(".") # => ""
|
||||
# normalize_dir("foo") # => "/foo"
|
||||
# normalize_dir("/foo/") # => "/foo"
|
||||
# normalize_dir("/") # => ""
|
||||
#
|
||||
# dir - String directory name.
|
||||
#
|
||||
# Returns a normalized String directory name, or nil if no directory
|
||||
# is given.
|
||||
def self.normalize_dir(dir)
|
||||
if dir
|
||||
dir = ::File.expand_path(dir, '/')
|
||||
dir = '' if dir == '/'
|
||||
end
|
||||
dir
|
||||
end
|
||||
end
|
||||
end
|
||||
+11
-6
@@ -33,6 +33,11 @@ module Gollum
|
||||
# Public: The String path of the file.
|
||||
attr_reader :path
|
||||
|
||||
# Public: The String mime type of the file.
|
||||
def mime_type
|
||||
@blob.mime_type
|
||||
end
|
||||
|
||||
#########################################################################
|
||||
#
|
||||
# Internal Methods
|
||||
@@ -46,14 +51,14 @@ module Gollum
|
||||
#
|
||||
# Returns a Gollum::File or nil if the file could not be found.
|
||||
def find(name, version)
|
||||
commit = @wiki.repo.commit(version)
|
||||
if blob = commit.tree / name
|
||||
@blob = blob
|
||||
checked = name.downcase
|
||||
map = @wiki.tree_map_for(version)
|
||||
sha = @wiki.ref_map[version] || version
|
||||
if entry = map.detect { |entry| entry.path.downcase == checked }
|
||||
@path = name
|
||||
@version = commit
|
||||
@blob = Grit::Blob.create(@wiki.repo, :id => entry.sha, :name => entry.name)
|
||||
@version = Grit::Commit.create(@wiki.repo, :id => sha)
|
||||
self
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+34
-24
@@ -1,3 +1,4 @@
|
||||
require 'cgi'
|
||||
require 'sinatra'
|
||||
require 'gollum'
|
||||
require 'mustache/sinatra'
|
||||
@@ -12,6 +13,7 @@ module Precious
|
||||
dir = File.dirname(File.expand_path(__FILE__))
|
||||
|
||||
# We want to serve public assets for now
|
||||
|
||||
set :public, "#{dir}/public"
|
||||
set :static, true
|
||||
|
||||
@@ -38,9 +40,9 @@ module Precious
|
||||
show_page_or_file('Home')
|
||||
end
|
||||
|
||||
get '/edit/:name' do
|
||||
@name = params[:name]
|
||||
wiki = Gollum::Wiki.new($path)
|
||||
get '/edit/*' do
|
||||
@name = params[:splat].first
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path)
|
||||
if page = wiki.page(@name)
|
||||
@page = page
|
||||
@content = page.raw_data
|
||||
@@ -50,38 +52,43 @@ module Precious
|
||||
end
|
||||
end
|
||||
|
||||
post '/edit/:name' do
|
||||
name = params[:name]
|
||||
wiki = Gollum::Wiki.new($path)
|
||||
post '/edit/*' do
|
||||
name = params[:splat].first
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path)
|
||||
page = wiki.page(name)
|
||||
format = params[:format].intern
|
||||
name = params[:rename] if params[:rename]
|
||||
|
||||
wiki.update_page(page, name, format, params[:content], commit_message)
|
||||
|
||||
redirect "/#{Gollum::Page.cname name}"
|
||||
redirect "/#{CGI.escape(Gollum::Page.cname(name))}"
|
||||
end
|
||||
|
||||
post '/create/:name' do
|
||||
post '/create/*' do
|
||||
name = params[:page]
|
||||
wiki = Gollum::Wiki.new($path)
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path)
|
||||
|
||||
format = params[:format].intern
|
||||
|
||||
wiki.write_page(name, format, params[:content], commit_message)
|
||||
redirect "/#{name}"
|
||||
begin
|
||||
wiki.write_page(name, format, params[:content], commit_message)
|
||||
redirect "/#{CGI.escape(name)}"
|
||||
rescue Gollum::DuplicatePageError => e
|
||||
@message = "Duplicate page: #{e.message}"
|
||||
mustache :error
|
||||
end
|
||||
end
|
||||
|
||||
post '/preview' do
|
||||
format = params['wiki_format']
|
||||
data = params['text']
|
||||
wiki = Gollum::Wiki.new($path)
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path)
|
||||
wiki.preview_page("Preview", data, format).formatted_data
|
||||
end
|
||||
|
||||
get '/history/:name' do
|
||||
@name = params[:name]
|
||||
wiki = Gollum::Wiki.new($path)
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path)
|
||||
@page = wiki.page(@name)
|
||||
@page_num = [params[:page].to_i, 1].max
|
||||
@versions = @page.versions :page => @page_num
|
||||
@@ -91,10 +98,10 @@ module Precious
|
||||
post '/compare/:name' do
|
||||
@versions = params[:versions] || []
|
||||
if @versions.size < 2
|
||||
redirect "/history/#{params[:name]}"
|
||||
redirect "/history/#{CGI.escape(params[:name])}"
|
||||
else
|
||||
redirect "/compare/%s/%s...%s" % [
|
||||
params[:name],
|
||||
CGI.escape(params[:name]),
|
||||
@versions.last,
|
||||
@versions.first]
|
||||
end
|
||||
@@ -103,7 +110,7 @@ module Precious
|
||||
get '/compare/:name/:version_list' do
|
||||
@name = params[:name]
|
||||
@versions = params[:version_list].split(/\.{2,3}/)
|
||||
wiki = Gollum::Wiki.new($path)
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path)
|
||||
@page = wiki.page(@name)
|
||||
diffs = wiki.repo.diff(@versions.first, @versions.last, @page.path)
|
||||
@diff = diffs.first
|
||||
@@ -112,7 +119,7 @@ module Precious
|
||||
|
||||
get %r{/(.+?)/([0-9a-f]{40})} do
|
||||
name = params[:captures][0]
|
||||
wiki = Gollum::Wiki.new($path)
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path)
|
||||
if page = wiki.page(name, params[:captures][1])
|
||||
@page = page
|
||||
@name = name
|
||||
@@ -123,18 +130,26 @@ module Precious
|
||||
end
|
||||
end
|
||||
|
||||
get '/search' do
|
||||
@query = params[:q]
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path)
|
||||
@results = wiki.search @query
|
||||
mustache :search
|
||||
end
|
||||
|
||||
get '/*' do
|
||||
show_page_or_file(params[:splat].first)
|
||||
end
|
||||
|
||||
def show_page_or_file(name)
|
||||
wiki = Gollum::Wiki.new($path)
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path)
|
||||
if page = wiki.page(name)
|
||||
@page = page
|
||||
@name = name
|
||||
@content = page.formatted_data
|
||||
mustache :page
|
||||
elsif file = wiki.file(name)
|
||||
content_type file.mime_type
|
||||
file.raw_data
|
||||
else
|
||||
@name = name
|
||||
@@ -143,12 +158,7 @@ module Precious
|
||||
end
|
||||
|
||||
def commit_message
|
||||
message = params[:message]
|
||||
author_name = `git config --get user.name`.strip || 'Anonymous'
|
||||
author_email = `git config --get user.email`.strip || 'anon@anon.com'
|
||||
{ :message => message,
|
||||
:name => author_name,
|
||||
:email => author_email }
|
||||
{ :message => params[:message] }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class="guide">
|
||||
<div class="main">
|
||||
<div class="actions">
|
||||
<a href="/{{name}}">« Back</a>
|
||||
<a href="/{{escaped_name}}">« Back</a>
|
||||
</div>
|
||||
<h1>{{title}}: {{before}} → {{after}}</h1>
|
||||
<div id="files">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<a href="/">« Home</a>
|
||||
<h1>{{title}}</h1>
|
||||
|
||||
<form class="new_wiki" method="post" action="/create/{{name}}">
|
||||
<form class="new_wiki" method="post" action="/create/{{escaped_name}}">
|
||||
<div>
|
||||
<label>
|
||||
Title<br />
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<div class="write">
|
||||
<a href="/{{name}}">« Back</a>
|
||||
<a href="/{{escaped_name}}">« Back</a>
|
||||
<h1>{{title}}</h1>
|
||||
|
||||
<form class="edit_wiki" method="post" action="/edit/{{name}}">
|
||||
<form class="edit_wiki" method="post" action="/edit/{{escaped_name}}">
|
||||
<div>
|
||||
<label>
|
||||
Title<br />
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<div class="guide">
|
||||
<div class="main">
|
||||
<div class="actions">
|
||||
<a href="/">Home</a>
|
||||
</div>
|
||||
<h1>Error</h1>
|
||||
<div class="error">
|
||||
{{message}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,10 +1,10 @@
|
||||
<div class="guide">
|
||||
<div class="main">
|
||||
<div class="actions">
|
||||
<a href="/{{name}}">« Back</a>
|
||||
<a href="/{{escaped_name}}">« Back</a>
|
||||
</div>
|
||||
<h1>{{title}}</h1>
|
||||
<form id="history" method="post" action="/compare/{{name}}">
|
||||
<form id="history" method="post" action="/compare/{{escaped_name}}">
|
||||
<table class="commits" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<th colspan="5">
|
||||
@@ -17,7 +17,7 @@
|
||||
<input name="versions[]" type="checkbox" value="{{id}}" />
|
||||
</td>
|
||||
<td class="sha">
|
||||
<a href="/{{name}}/{{id}}">{{id7}}</a>
|
||||
<a href="/{{escaped_name}}/{{id}}">{{id7}}</a>
|
||||
</td>
|
||||
<td nowrap class="author">
|
||||
<img src="http://www.gravatar.com/avatar/{{gravatar}}?s=16" alt="Gravatar" />
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
<div class="guide">
|
||||
<div class="main">
|
||||
<div class="actions">
|
||||
<a href="/">Home</a> | <a href="/edit/{{name}}">Edit</a>
|
||||
<form action="/search" method="get">
|
||||
<div>
|
||||
<a href="/">Home</a> |
|
||||
<a href="/edit/{{escaped_name}}">Edit</a> |
|
||||
<input type="search" name="q" size="10" /> <input type="submit" value="search" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<h1>{{title}}</h1>
|
||||
<div class="content wikistyle gollum {{format}}">
|
||||
@@ -18,10 +24,10 @@
|
||||
<div style="float: left;">
|
||||
<small>Last edited by <b>{{author}}</b>, {{date}}</small>
|
||||
<div class="actions">
|
||||
<a href="/">Home</a> | <a href="/edit/{{name}}">Edit</a>
|
||||
<a href="/">Home</a> | <a href="/edit/{{escaped_name}}">Edit</a>
|
||||
</div>
|
||||
</div>
|
||||
<div style="float: right;">
|
||||
<a href="/history/{{name}}">View Revision History</a>
|
||||
<a href="/history/{{escaped_name}}">View Revision History</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<div class="guide">
|
||||
<div class="main">
|
||||
<div class="actions">
|
||||
<form action="/search" method="get">
|
||||
<a href="/">Home</a> | <input type="search" name="q" size="10" /> <input type="submit" value="search" />
|
||||
</form>
|
||||
</div>
|
||||
<h1>Search for “{{query}}”</h1>
|
||||
<div class="content wikistyle gollum">
|
||||
{{#has_results}}
|
||||
<ul>
|
||||
{{#results}}
|
||||
<li><a href="/{{name}}">{{name}} ({{count}})</a></li>
|
||||
{{/results}}
|
||||
</ul>
|
||||
{{/has_results}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
module Precious
|
||||
module Views
|
||||
class Error < Layout
|
||||
attr_reader :message
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'cgi'
|
||||
|
||||
module Precious
|
||||
module Views
|
||||
class Layout < Mustache
|
||||
@@ -6,6 +8,10 @@ module Precious
|
||||
|
||||
attr_reader :name
|
||||
|
||||
def escaped_name
|
||||
CGI.escape(@name)
|
||||
end
|
||||
|
||||
def title
|
||||
"Home"
|
||||
end
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
module Precious
|
||||
module Views
|
||||
class Search < Layout
|
||||
attr_reader :content, :page, :footer, :results, :query
|
||||
|
||||
def has_results
|
||||
!@results.empty?
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
+73
-29
@@ -1,4 +1,5 @@
|
||||
require 'digest/sha1'
|
||||
require 'cgi'
|
||||
|
||||
module Gollum
|
||||
class Markup
|
||||
@@ -21,8 +22,14 @@ module Gollum
|
||||
# Render the content with Gollum wiki syntax on top of the file's own
|
||||
# markup language.
|
||||
#
|
||||
# no_follow - Boolean that determines if rel="nofollow" is added to all
|
||||
# <a> tags.
|
||||
#
|
||||
# Returns the formatted String content.
|
||||
def render
|
||||
def render(no_follow = false)
|
||||
sanitize_options = no_follow ?
|
||||
HISTORY_SANITIZATION_OPTIONS :
|
||||
SANITIZATION_OPTIONS
|
||||
data = extract_tex(@data)
|
||||
data = extract_code(data)
|
||||
data = extract_tags(data)
|
||||
@@ -36,9 +43,9 @@ module Gollum
|
||||
end
|
||||
data = process_tags(data)
|
||||
data = process_code(data)
|
||||
data = Sanitize.clean(data, SANITIZATION_OPTIONS)
|
||||
data = Sanitize.clean(data, sanitize_options)
|
||||
data = process_tex(data)
|
||||
data = data.gsub(/<p><\/p>/, '')
|
||||
data.gsub!(/<p><\/p>/, '')
|
||||
data
|
||||
end
|
||||
|
||||
@@ -114,28 +121,33 @@ module Gollum
|
||||
# Process all tags from the tagmap and replace the placeholders with the
|
||||
# final markup.
|
||||
#
|
||||
# data - The String data (with placeholders).
|
||||
# data - The String data (with placeholders).
|
||||
# no_follow - Boolean that determines if rel="nofollow" is added to all
|
||||
# <a> tags.
|
||||
#
|
||||
# Returns the marked up String data.
|
||||
def process_tags(data)
|
||||
def process_tags(data, no_follow = false)
|
||||
@tagmap.each do |id, tag|
|
||||
data.gsub!(id, process_tag(tag))
|
||||
data.gsub!(id, process_tag(tag, no_follow))
|
||||
end
|
||||
data
|
||||
end
|
||||
|
||||
# Process a single tag into its final HTML form.
|
||||
#
|
||||
# tag - The String tag contents (the stuff inside the double brackets).
|
||||
# tag - The String tag contents (the stuff inside the double
|
||||
# brackets).
|
||||
# no_follow - Boolean that determines if rel="nofollow" is added to all
|
||||
# <a> tags.
|
||||
#
|
||||
# Returns the String HTML version of the tag.
|
||||
def process_tag(tag)
|
||||
def process_tag(tag, no_follow = false)
|
||||
if html = process_image_tag(tag)
|
||||
return html
|
||||
elsif html = process_file_link_tag(tag)
|
||||
return html
|
||||
html
|
||||
elsif html = process_file_link_tag(tag, no_follow)
|
||||
html
|
||||
else
|
||||
return process_page_link_tag(tag)
|
||||
process_page_link_tag(tag, no_follow)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -150,7 +162,7 @@ module Gollum
|
||||
name = parts[0].strip
|
||||
path = if file = find_file(name)
|
||||
::File.join @wiki.base_path, file.path
|
||||
elsif name =~ /^https?:\/\/.+(jpg|png|gif|svg|bmp)$/
|
||||
elsif name =~ /^https?:\/\/.+(jpg|png|gif|svg|bmp)$/i
|
||||
name
|
||||
end
|
||||
|
||||
@@ -200,7 +212,7 @@ module Gollum
|
||||
classes << 'frame' if opts['frame']
|
||||
%{<span class="#{classes.join(' ')}">} +
|
||||
%{<span>} +
|
||||
%{<img src="/#{file.path}" #{attr_string}/>} +
|
||||
%{<img src="#{path}" #{attr_string}/>} +
|
||||
(alt ? %{<span>#{alt}</span>} : '') +
|
||||
%{</span>} +
|
||||
%{</span>}
|
||||
@@ -228,11 +240,14 @@ module Gollum
|
||||
|
||||
# Attempt to process the tag as a file link tag.
|
||||
#
|
||||
# tag - The String tag contents (the stuff inside the double brackets).
|
||||
# tag - The String tag contents (the stuff inside the double
|
||||
# brackets).
|
||||
# no_follow - Boolean that determines if rel="nofollow" is added to all
|
||||
# <a> tags.
|
||||
#
|
||||
# Returns the String HTML if the tag is a valid file link tag or nil
|
||||
# if it is not.
|
||||
def process_file_link_tag(tag)
|
||||
def process_file_link_tag(tag, no_follow = false)
|
||||
parts = tag.split('|')
|
||||
name = parts[0].strip
|
||||
path = parts[1] && parts[1].strip
|
||||
@@ -244,37 +259,49 @@ module Gollum
|
||||
nil
|
||||
end
|
||||
|
||||
if name && path && file
|
||||
tag = if name && path && file
|
||||
%{<a href="#{::File.join @wiki.base_path, file.path}">#{name}</a>}
|
||||
elsif name && path
|
||||
%{<a href="#{path}">#{name}</a>}
|
||||
else
|
||||
nil
|
||||
end
|
||||
if tag && no_follow
|
||||
tag.sub! /^<a/, '<a ref="nofollow"'
|
||||
end
|
||||
tag
|
||||
end
|
||||
|
||||
# Attempt to process the tag as a page link tag.
|
||||
#
|
||||
# tag - The String tag contents (the stuff inside the double brackets).
|
||||
# tag - The String tag contents (the stuff inside the double
|
||||
# brackets).
|
||||
# no_follow - Boolean that determines if rel="nofollow" is added to all
|
||||
# <a> tags.
|
||||
#
|
||||
# Returns the String HTML if the tag is a valid page link tag or nil
|
||||
# if it is not.
|
||||
def process_page_link_tag(tag)
|
||||
def process_page_link_tag(tag, no_follow = false)
|
||||
parts = tag.split('|')
|
||||
name = parts[0].strip
|
||||
cname = Page.cname((parts[1] || parts[0]).strip)
|
||||
if name =~ %r{^https?://} && parts[1].nil?
|
||||
tag = if name =~ %r{^https?://} && parts[1].nil?
|
||||
%{<a href="#{name}">#{name}</a>}
|
||||
else
|
||||
if page = @wiki.page(cname)
|
||||
link = ::File.join(@wiki.base_path, Page.cname(page.name))
|
||||
presence = "present"
|
||||
else
|
||||
link = ::File.join(@wiki.base_path, cname)
|
||||
presence = "absent"
|
||||
presence = "absent"
|
||||
link_name = cname
|
||||
page, extra = find_page_from_name(cname)
|
||||
if page
|
||||
link_name = Page.cname(page.name)
|
||||
presence = "present"
|
||||
end
|
||||
%{<a class="internal #{presence}" href="#{link}">#{name}</a>}
|
||||
link = ::File.join(@wiki.base_path, CGI.escape(link_name))
|
||||
%{<a class="internal #{presence}" href="#{link}#{extra}">#{name}</a>}
|
||||
end
|
||||
if tag && no_follow
|
||||
tag.sub! /^<a/, '<a ref="nofollow"'
|
||||
end
|
||||
tag
|
||||
end
|
||||
|
||||
# Find the given file in the repo.
|
||||
@@ -291,6 +318,23 @@ module Gollum
|
||||
end
|
||||
end
|
||||
|
||||
# Find a page from a given cname. If the page has an anchor (#) and has
|
||||
# no match, strip the anchor and try again.
|
||||
#
|
||||
# cname - The String canonical page name.
|
||||
#
|
||||
# Returns a Gollum::Page instance if a page is found, or an Array of
|
||||
# [Gollum::Page, String extra] if a page without the extra anchor data
|
||||
# is found.
|
||||
def find_page_from_name(cname)
|
||||
if page = @wiki.page(cname)
|
||||
return page
|
||||
end
|
||||
if pos = cname.index('#')
|
||||
[@wiki.page(cname[0...pos]), cname[pos..-1]]
|
||||
end
|
||||
end
|
||||
|
||||
#########################################################################
|
||||
#
|
||||
# Code
|
||||
@@ -320,7 +364,7 @@ module Gollum
|
||||
@codemap.each do |id, spec|
|
||||
lang = spec[:lang]
|
||||
code = spec[:code]
|
||||
if code.all? { |line| line =~ /\A\r?\n\Z/ || line =~ /^( |\t)/ }
|
||||
if code.lines.all? { |line| line =~ /\A\r?\n\Z/ || line =~ /^( |\t)/ }
|
||||
code.gsub!(/^( |\t)/m, '')
|
||||
end
|
||||
data.gsub!(id, Gollum::Albino.new(code, lang).colorize)
|
||||
@@ -328,4 +372,4 @@ module Gollum
|
||||
data
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+49
-56
@@ -14,6 +14,11 @@ module Gollum
|
||||
:asciidoc => "AsciiDoc",
|
||||
:pod => "Pod" }
|
||||
|
||||
# Sets a Boolean determing whether this page is a historical version.
|
||||
#
|
||||
# Returns nothing.
|
||||
attr_writer :historical
|
||||
|
||||
# Checks if a filename has a valid extension understood by GitHub::Markup.
|
||||
#
|
||||
# filename - String filename, like "Home.md".
|
||||
@@ -35,6 +40,14 @@ module Gollum
|
||||
filename =~ /^_/ ? false : match
|
||||
end
|
||||
|
||||
# Reusable filter to turn a filename (without path) into a canonical name.
|
||||
# Strips extension, converts spaces to dashes.
|
||||
#
|
||||
# Returns the filtered String.
|
||||
def self.canonicalize_filename(filename)
|
||||
filename.split('.')[0..-2].join('.').gsub('-', ' ')
|
||||
end
|
||||
|
||||
# Public: Initialize a page.
|
||||
#
|
||||
# wiki - The Gollum::Wiki in question.
|
||||
@@ -57,7 +70,7 @@ module Gollum
|
||||
#
|
||||
# Returns the String name.
|
||||
def name
|
||||
filename.split('.')[0..-2].join('.').gsub('-', ' ')
|
||||
self.class.canonicalize_filename(filename)
|
||||
end
|
||||
|
||||
# Public: If the first element of a formatted page is an <h1> tag it can
|
||||
@@ -107,7 +120,7 @@ module Gollum
|
||||
#
|
||||
# Returns the String data.
|
||||
def formatted_data
|
||||
@blob && Gollum::Markup.new(self).render
|
||||
@blob && Gollum::Markup.new(self).render(historical?)
|
||||
end
|
||||
|
||||
# Public: The format of the page.
|
||||
@@ -174,20 +187,24 @@ module Gollum
|
||||
|
||||
dirs = self.path.split('/')
|
||||
dirs.pop
|
||||
map = @wiki.tree_map_for(self.version.id)
|
||||
while !dirs.empty?
|
||||
tree = self.version.tree / dirs.join('/')
|
||||
if page = find_page_in_this_tree(tree, dirs.join('/'), '_Footer')
|
||||
if page = find_page_in_tree(map, '_Footer', dirs.join('/'))
|
||||
return page
|
||||
end
|
||||
dirs.pop
|
||||
end
|
||||
|
||||
tree = self.version.tree
|
||||
if page = find_page_in_this_tree(tree, '', '_Footer')
|
||||
return page
|
||||
end
|
||||
find_page_in_tree(map, '_Footer', '')
|
||||
end
|
||||
|
||||
return nil
|
||||
# Gets a Boolean determining whether this page is a historical version.
|
||||
# Historical pages are pulled using exact SHA hashes and format all links
|
||||
# with rel="nofollow"
|
||||
#
|
||||
# Returns true if the page is pulled from a named branch or tag, or false.
|
||||
def historical?
|
||||
!!@historical
|
||||
end
|
||||
|
||||
#########################################################################
|
||||
@@ -207,7 +224,9 @@ module Gollum
|
||||
#
|
||||
# Returns the String canonical name.
|
||||
def self.cname(name)
|
||||
name.gsub(%r{[ /<>]}, '-')
|
||||
name.respond_to?(:gsub) ?
|
||||
name.gsub(%r{[ /<>]}, '-') :
|
||||
''
|
||||
end
|
||||
|
||||
# Convert a format Symbol into an extension String.
|
||||
@@ -251,61 +270,35 @@ module Gollum
|
||||
#
|
||||
# Returns a Gollum::Page or nil if the page could not be found.
|
||||
def find(name, version)
|
||||
if commit = @wiki.repo.commit(version)
|
||||
if page = find_page_in_tree(commit.tree, name)
|
||||
page.version = commit
|
||||
page
|
||||
end
|
||||
map = @wiki.tree_map_for(version)
|
||||
if page = find_page_in_tree(map, name)
|
||||
sha = @wiki.ref_map[version] || version
|
||||
page.version = Grit::Commit.create(@wiki.repo, :id => sha)
|
||||
page.historical = sha == version
|
||||
page
|
||||
end
|
||||
rescue Grit::GitRuby::Repository::NoSuchShaFound
|
||||
end
|
||||
|
||||
# Find a page in a given tree.
|
||||
#
|
||||
# tree - The Grit::Tree in which to look.
|
||||
# name - The canonical String page name.
|
||||
# map - The Array tree map from Wiki#tree_map.
|
||||
# name - The canonical String page name.
|
||||
# checked_dir - Optional String of the directory a matching page needs
|
||||
# to be in. The string should
|
||||
#
|
||||
# Returns a Gollum::Page or nil if the page could not be found.
|
||||
def find_page_in_tree(tree, name)
|
||||
treemap = {}
|
||||
trees = [tree]
|
||||
|
||||
while !trees.empty?
|
||||
ptree = trees.shift
|
||||
ptree.contents.each do |item|
|
||||
case item
|
||||
when Grit::Blob
|
||||
if page_match(name, item.name)
|
||||
return self.class.new(@wiki).populate(item, tree_path(treemap, ptree))
|
||||
end
|
||||
when Grit::Tree
|
||||
treemap[item] = ptree
|
||||
trees << item
|
||||
end
|
||||
end
|
||||
def find_page_in_tree(map, name, checked_dir = nil)
|
||||
return nil if name.to_s.empty?
|
||||
if checked_dir = BlobEntry.normalize_dir(checked_dir)
|
||||
checked_dir.downcase!
|
||||
end
|
||||
|
||||
return nil # nothing was found
|
||||
end
|
||||
|
||||
# Find a page in a given tree without recursing into subtrees.
|
||||
#
|
||||
# tree - The Grit::Tree in which to look.
|
||||
# dir - The String path of the given Grit::Tree.
|
||||
# name - The canonical String page name.
|
||||
#
|
||||
# Returns a Gollum::Page or nil if the page could not be found.
|
||||
def find_page_in_this_tree(tree, dir, name)
|
||||
treemap = {}
|
||||
tree.contents.each do |item|
|
||||
case item
|
||||
when Grit::Blob
|
||||
if page_match(name, item.name)
|
||||
path = dir == '' ? '' : ::File.join('/', dir)
|
||||
page = self.class.new(@wiki).populate(item, path)
|
||||
page.version = self.version
|
||||
return page
|
||||
end
|
||||
end
|
||||
map.each do |entry|
|
||||
next if entry.name.to_s.empty?
|
||||
next unless checked_dir.nil? || entry.dir.downcase == checked_dir
|
||||
next unless page_match(name, entry.name)
|
||||
return entry.page(@wiki, @version)
|
||||
end
|
||||
|
||||
return nil # nothing was found
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
class String
|
||||
alias :lines :to_a if defined?(RUBY_VERSION) && RUBY_VERSION < '1.9'
|
||||
end
|
||||
+314
-101
@@ -9,6 +9,12 @@ module Gollum
|
||||
# Sets the file class used by all instances of this Wiki.
|
||||
attr_writer :file_class
|
||||
|
||||
# Sets the default name for commits.
|
||||
attr_accessor :default_committer_name
|
||||
|
||||
# Sets the default email for commits.
|
||||
attr_accessor :default_committer_email
|
||||
|
||||
# Gets the page class used by all instances of this Wiki.
|
||||
# Default: Gollum::Page.
|
||||
def page_class
|
||||
@@ -32,6 +38,8 @@ module Gollum
|
||||
end
|
||||
end
|
||||
|
||||
self.default_committer_name = 'Anonymous'
|
||||
self.default_committer_email = 'anon@anon.com'
|
||||
|
||||
# The String base path to prefix to internal links. For example, when set
|
||||
# to "/wiki", the page "Hobbit" will be linked as "/wiki/Hobbit". Defaults
|
||||
@@ -43,7 +51,7 @@ module Gollum
|
||||
# repo - The String path to the Git repository that holds the Gollum
|
||||
# site.
|
||||
# options - Optional Hash:
|
||||
# :base_path - String base path for all Wiki links.
|
||||
# :base_path - String base path for all Wiki links.
|
||||
# Default: "/"
|
||||
# :page_class - The page Class. Default: Gollum::Page
|
||||
# :file_class - The file Class. Default: Gollum::File
|
||||
@@ -55,6 +63,7 @@ module Gollum
|
||||
@base_path = options[:base_path] || "/"
|
||||
@page_class = options[:page_class] || self.class.page_class
|
||||
@file_class = options[:file_class] || self.class.file_class
|
||||
clear_cache
|
||||
end
|
||||
|
||||
# Public: check whether the wiki's git repo exists on the filesystem.
|
||||
@@ -115,17 +124,23 @@ module Gollum
|
||||
#
|
||||
# Returns the String SHA1 of the newly written version.
|
||||
def write_page(name, format, data, commit = {})
|
||||
map = {}
|
||||
commit = normalize_commit(commit)
|
||||
index = self.repo.index
|
||||
|
||||
if pcommit = @repo.commit('master')
|
||||
map = tree_map(pcommit.tree)
|
||||
index.read_tree(pcommit.tree.id)
|
||||
end
|
||||
|
||||
map = add_to_tree_map(map, '', name, format, data)
|
||||
index = tree_map_to_index(map)
|
||||
add_to_index(index, '', name, format, data)
|
||||
|
||||
parents = pcommit ? [pcommit] : []
|
||||
actor = Grit::Actor.new(commit[:name], commit[:email])
|
||||
index.commit(commit[:message], parents, actor)
|
||||
sha1 = index.commit(commit[:message], parents, actor)
|
||||
|
||||
@ref_map.clear
|
||||
update_working_dir(index, '', name, format)
|
||||
|
||||
sha1
|
||||
end
|
||||
|
||||
# Public: Update an existing page with new content. The location of the
|
||||
@@ -144,24 +159,32 @@ module Gollum
|
||||
#
|
||||
# Returns the String SHA1 of the newly written version.
|
||||
def update_page(page, name, format, data, commit = {})
|
||||
commit = normalize_commit(commit)
|
||||
pcommit = @repo.commit('master')
|
||||
map = tree_map(pcommit.tree)
|
||||
name ||= page.name
|
||||
format ||= page.format
|
||||
index = nil
|
||||
index = self.repo.index
|
||||
|
||||
dir = ::File.dirname(page.path)
|
||||
dir = '' if dir == '.'
|
||||
|
||||
index.read_tree(pcommit.tree.id)
|
||||
|
||||
if page.name == name && page.format == format
|
||||
index = tree_map_to_index(map)
|
||||
index.add(page.path, normalize(data))
|
||||
else
|
||||
map = delete_from_tree_map(map, page.path)
|
||||
dir = ::File.dirname(page.path)
|
||||
map = add_to_tree_map(map, dir, name, format, data)
|
||||
index = tree_map_to_index(map)
|
||||
index.delete(page.path)
|
||||
add_to_index(index, dir, name, format, data, :allow_same_ext)
|
||||
end
|
||||
|
||||
actor = Grit::Actor.new(commit[:name], commit[:email])
|
||||
index.commit(commit[:message], [pcommit], actor)
|
||||
sha1 = index.commit(commit[:message], [pcommit], actor)
|
||||
|
||||
@ref_map.clear
|
||||
update_working_dir(index, dir, page.name, page.format)
|
||||
update_working_dir(index, dir, name, format)
|
||||
|
||||
sha1
|
||||
end
|
||||
|
||||
# Public: Delete a page.
|
||||
@@ -169,19 +192,27 @@ module Gollum
|
||||
# page - The Gollum::Page to delete.
|
||||
# commit - The commit Hash details:
|
||||
# :message - The String commit message.
|
||||
# :author - The String author full name.
|
||||
# :name - The String author full name.
|
||||
# :email - The String email address.
|
||||
#
|
||||
# Returns the String SHA1 of the newly written version.
|
||||
def delete_page(page, commit)
|
||||
pcommit = @repo.commit('master')
|
||||
map = tree_map(pcommit.tree)
|
||||
|
||||
map = delete_from_tree_map(map, page.path)
|
||||
index = tree_map_to_index(map)
|
||||
index = self.repo.index
|
||||
index.read_tree(pcommit.tree.id)
|
||||
index.delete(page.path)
|
||||
|
||||
dir = ::File.dirname(page.path)
|
||||
dir = '' if dir == '.'
|
||||
|
||||
actor = Grit::Actor.new(commit[:name], commit[:email])
|
||||
index.commit(commit[:message], [pcommit], actor)
|
||||
sha1 = index.commit(commit[:message], [pcommit], actor)
|
||||
|
||||
@ref_map.clear
|
||||
update_working_dir(index, dir, page.name, page.format)
|
||||
|
||||
sha1
|
||||
end
|
||||
|
||||
# Public: Lists all pages for this wiki.
|
||||
@@ -190,11 +221,39 @@ module Gollum
|
||||
#
|
||||
# Returns an Array of Gollum::Page instances.
|
||||
def pages(treeish = nil)
|
||||
treeish ||= 'master'
|
||||
if commit = @repo.commit(treeish)
|
||||
tree_list(commit)
|
||||
else
|
||||
[]
|
||||
tree_list(treeish || 'master')
|
||||
end
|
||||
|
||||
# Public: Returns the number of pages accessible from a commit
|
||||
#
|
||||
# ref - A String ref that is either a commit SHA or references one.
|
||||
#
|
||||
# Returns a Fixnum
|
||||
def size(ref = nil)
|
||||
tree_map_for(ref || 'master').inject(0) do |num, entry|
|
||||
num + (@page_class.valid_page_name?(entry.name) ? 1 : 0)
|
||||
end
|
||||
rescue Grit::GitRuby::Repository::NoSuchShaFound
|
||||
0
|
||||
end
|
||||
|
||||
# Public: Search all pages for this wiki.
|
||||
#
|
||||
# query - The string to search for
|
||||
#
|
||||
# Returns an Array with Objects of page name and count of matches
|
||||
def search(query)
|
||||
# See: http://github.com/Sirupsen/gollum/commit/f0a6f52bdaf6bee8253ca33bb3fceaeb27bfb87e
|
||||
search_output = @repo.git.grep({:c => query}, 'master')
|
||||
|
||||
search_output.split("\n").collect do |line|
|
||||
result = line.split(':')
|
||||
file_name = Gollum::Page.canonicalize_filename(::File.basename(result[1]))
|
||||
|
||||
{
|
||||
:count => result[2].to_i,
|
||||
:name => file_name
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -225,6 +284,26 @@ module Gollum
|
||||
# Returns the String path.
|
||||
attr_reader :path
|
||||
|
||||
# Gets a Hash cache of refs to commit SHAs.
|
||||
#
|
||||
# {"master" => "abc123", ...}
|
||||
#
|
||||
# Returns the Hash cache.
|
||||
attr_reader :ref_map
|
||||
|
||||
# Gets a Hash cache of commit SHAs to a recursive tree of blobs.
|
||||
#
|
||||
# {"abc123" => [["lib/foo.rb", "blob-sha"], [file, sha], ...], ...}
|
||||
#
|
||||
# Returns the Hash cache.
|
||||
attr_reader :tree_map
|
||||
|
||||
# Gets the page class used by all instances of this Wiki.
|
||||
attr_reader :page_class
|
||||
|
||||
# Gets the file class used by all instances of this Wiki.
|
||||
attr_reader :file_class
|
||||
|
||||
# Normalize the data.
|
||||
#
|
||||
# data - The String data to be normalized.
|
||||
@@ -234,102 +313,236 @@ module Gollum
|
||||
data.gsub(/\r/, '')
|
||||
end
|
||||
|
||||
# Assemble a Page's filename from its name and format.
|
||||
#
|
||||
# name - The String name of the page (may be in human format).
|
||||
# format - The Symbol format of the page.
|
||||
#
|
||||
# Returns the String filename.
|
||||
def page_file_name(name, format)
|
||||
ext = @page_class.format_to_ext(format)
|
||||
@page_class.cname(name) + '.' + ext
|
||||
end
|
||||
|
||||
# Update the given file in the repository's working directory if there
|
||||
# is a working directory present.
|
||||
#
|
||||
# index - The Grit::Index with which to sync.
|
||||
# dir - The String directory in which the file lives.
|
||||
# name - The String name of the page (may be in human format).
|
||||
# format - The Symbol format of the page.
|
||||
#
|
||||
# Returns nothing.
|
||||
def update_working_dir(index, dir, name, format)
|
||||
unless @repo.bare
|
||||
path =
|
||||
if dir == ''
|
||||
page_file_name(name, format)
|
||||
else
|
||||
::File.join(dir, page_file_name(name, format))
|
||||
end
|
||||
|
||||
Dir.chdir(::File.join(@repo.path, '..')) do
|
||||
if file_path_scheduled_for_deletion?(index.tree, path)
|
||||
@repo.git.rm({'f' => true}, '--', path)
|
||||
else
|
||||
@repo.git.checkout({}, 'HEAD', '--', path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Fill an array with a list of pages.
|
||||
#
|
||||
# commit - The Grit::Commit
|
||||
# tree - The Grit::Tree to start with.
|
||||
# sub_tree - Optional String specifying the parent path of the Page.
|
||||
# ref - A String ref that is either a commit SHA or references one.
|
||||
#
|
||||
# Returns a flat Array of Gollum::Page instances.
|
||||
def tree_list(commit, tree = commit.tree, sub_tree = nil)
|
||||
list = []
|
||||
path = tree.name ? "#{sub_tree}/#{tree.name}" : ''
|
||||
tree.contents.each do |item|
|
||||
case item
|
||||
when Grit::Blob
|
||||
if @page_class.valid_page_name?(item.name)
|
||||
page = @page_class.new(self).populate(item, path)
|
||||
page.version = commit
|
||||
list << page
|
||||
end
|
||||
when Grit::Tree
|
||||
list.push *tree_list(commit, item, path)
|
||||
end
|
||||
def tree_list(ref)
|
||||
tree_map_for(ref).inject([]) do |list, entry|
|
||||
next list unless @page_class.valid_page_name?(entry.name)
|
||||
sha = ref_map[ref]
|
||||
list << entry.page(self, @repo.commit(sha))
|
||||
end
|
||||
list
|
||||
end
|
||||
|
||||
# Fill an index with the existing state of the repository.
|
||||
#
|
||||
# tree - The Grit::Tree to start with.
|
||||
#
|
||||
# Returns a nested Hash of filename to content mappings.
|
||||
def tree_map(tree)
|
||||
map = {}
|
||||
tree.contents.each do |item|
|
||||
case item
|
||||
when Grit::Blob
|
||||
map[item.name] = item.data
|
||||
when Grit::Tree
|
||||
map[item.name] = tree_map(item)
|
||||
end
|
||||
end
|
||||
map
|
||||
end
|
||||
|
||||
# Use a treemap to fill in the index.
|
||||
# Determine if a given file is scheduled to be deleted in the next commit
|
||||
# for the given Index.
|
||||
#
|
||||
# map - The Hash map:
|
||||
# key - The String directory or filename.
|
||||
# val - The Hash submap or the String contents of the file.
|
||||
# index - The Grit::Index to use. Leave blank when calling from outside
|
||||
# this method (default: nil).
|
||||
# path - The String path of the file including extension.
|
||||
#
|
||||
# Returns the Grit::Index.
|
||||
def tree_map_to_index(map, prefix = '', index = nil)
|
||||
index ||= @repo.index
|
||||
map.each do |k, v|
|
||||
case k
|
||||
when String
|
||||
name = [prefix, k].join('/')[1..-1]
|
||||
index.add(k, v)
|
||||
when Hash
|
||||
new_prefix = [prefix, k].join('/')[1..-1]
|
||||
tree_map_to_index(v, new_prefix, index)
|
||||
# Returns the Boolean response.
|
||||
def file_path_scheduled_for_deletion?(map, path)
|
||||
parts = path.split('/')
|
||||
if parts.size == 1
|
||||
deletions = map.keys.select { |k| !map[k] }
|
||||
deletions.any? { |d| d == parts.first }
|
||||
else
|
||||
part = parts.shift
|
||||
if rest = map[part]
|
||||
file_path_scheduled_for_deletion?(rest, parts.join('/'))
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
index
|
||||
end
|
||||
|
||||
def add_to_tree_map(map, dir, name, format, data)
|
||||
ext = @page_class.format_to_ext(format)
|
||||
path = @page_class.cname(name) + '.' + ext
|
||||
|
||||
parts = dir.split('/')
|
||||
container = nil
|
||||
parts.each do |part|
|
||||
container = map[part]
|
||||
end
|
||||
|
||||
(container || map)[path] = normalize(data)
|
||||
map
|
||||
end
|
||||
|
||||
# Delete an entry from a tree map.
|
||||
# Determine if a given page (regardless of format) is scheduled to be
|
||||
# deleted in the next commit for the given Index.
|
||||
#
|
||||
# map - The Hash tree map of the repository.
|
||||
# path - The String path of the file to delete.
|
||||
# map - The Hash map:
|
||||
# key - The String directory or filename.
|
||||
# val - The Hash submap or the String contents of the file.
|
||||
# path - The String path of the page file. This may include the format
|
||||
# extension in which case it will be ignored.
|
||||
#
|
||||
# Returns the modified Hash tree map.
|
||||
def delete_from_tree_map(map, path)
|
||||
# Returns the Boolean response.
|
||||
def page_path_scheduled_for_deletion?(map, path)
|
||||
parts = path.split('/')
|
||||
name = parts.pop
|
||||
container = nil
|
||||
parts.each do |part|
|
||||
container = map[part]
|
||||
if parts.size == 1
|
||||
deletions = map.keys.select { |k| !map[k] }
|
||||
downfile = parts.first.downcase.sub(/\.\w+$/, '')
|
||||
deletions.any? { |d| d.downcase.sub(/\.\w+$/, '') == downfile }
|
||||
else
|
||||
part = parts.shift
|
||||
if rest = map[part]
|
||||
page_path_scheduled_for_deletion?(rest, parts.join('/'))
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
(container || map).delete(name)
|
||||
map
|
||||
end
|
||||
|
||||
# Adds a page to the given Index.
|
||||
#
|
||||
# index - The Grit::Index to which the page will be added.
|
||||
# dir - The String subdirectory of the Gollum::Page without any
|
||||
# prefix or suffix slashes (e.g. "foo/bar").
|
||||
# name - The String Gollum::Page name.
|
||||
# format - The Symbol Gollum::Page format.
|
||||
# data - The String wiki data to store in the tree map.
|
||||
# allow_same_ext - A Boolean determining if the tree map allows the same
|
||||
# filename with the same extension.
|
||||
#
|
||||
# Raises Gollum::DuplicatePageError if a matching filename already exists.
|
||||
# This way, pages are not inadvertently overwritten.
|
||||
#
|
||||
# Returns nothing (modifies the Index in place).
|
||||
def add_to_index(index, dir, name, format, data, allow_same_ext = false)
|
||||
path = page_file_name(name, format)
|
||||
|
||||
dir = '/' if dir.strip.empty?
|
||||
|
||||
fullpath = ::File.join(dir, path)
|
||||
fullpath = fullpath[1..-1] if fullpath =~ /^\//
|
||||
|
||||
if index.current_tree && tree = index.current_tree / dir
|
||||
downpath = path.downcase.sub(/\.\w+$/, '')
|
||||
|
||||
tree.blobs.each do |blob|
|
||||
next if page_path_scheduled_for_deletion?(index.tree, fullpath)
|
||||
file = blob.name.downcase.sub(/\.\w+$/, '')
|
||||
file_ext = ::File.extname(blob.name).sub(/^\./, '')
|
||||
if downpath == file && !(allow_same_ext && file_ext == ext)
|
||||
raise DuplicatePageError.new(dir, blob.name, path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
index.add(fullpath, normalize(data))
|
||||
end
|
||||
|
||||
# Ensures a commit hash has all the required fields for a commit.
|
||||
#
|
||||
# commit - The commit Hash details:
|
||||
# :message - The String commit message.
|
||||
# :name - The String author full name.
|
||||
# :email - The String email address.
|
||||
#
|
||||
# Returns the commit Hash
|
||||
def normalize_commit(commit = {})
|
||||
commit[:name] = default_committer_name if commit[:name].to_s.empty?
|
||||
commit[:email] = default_committer_email if commit[:email].to_s.empty?
|
||||
commit
|
||||
end
|
||||
|
||||
# Gets the default name for commits.
|
||||
def default_committer_name
|
||||
@default_committer_name ||= \
|
||||
@repo.config['user.name'] || self.class.default_committer_name
|
||||
end
|
||||
|
||||
# Gets the default email for commits.
|
||||
def default_committer_email
|
||||
@default_committer_email ||= \
|
||||
@repo.config['user.email'] || self.class.default_committer_email
|
||||
end
|
||||
|
||||
# Finds a full listing of files and their blob SHA for a given ref. Each
|
||||
# listing is cached based on its actual commit SHA.
|
||||
#
|
||||
# ref - A String ref that is either a commit SHA or references one.
|
||||
#
|
||||
# Returns an Array of BlobEntry instances.
|
||||
def tree_map_for(ref)
|
||||
sha = @ref_map[ref] || ref
|
||||
@tree_map[sha] || begin
|
||||
real_sha = @repo.git.rev_list({:max_count=>1}, ref)
|
||||
@ref_map[ref] = real_sha if real_sha != ref
|
||||
@tree_map[real_sha] ||= parse_tree_for(real_sha)
|
||||
end
|
||||
rescue Grit::GitRuby::Repository::NoSuchShaFound
|
||||
[]
|
||||
end
|
||||
|
||||
# Finds the full listing of files and their blob SHA for a given commit
|
||||
# SHA. No caching or ref lookups are performed.
|
||||
#
|
||||
# sha - String commit SHA.
|
||||
#
|
||||
# Returns an Array of BlobEntry instances.
|
||||
def parse_tree_for(sha)
|
||||
tree = @repo.git.native(:ls_tree, {:r => true, :z => true}, sha)
|
||||
items = []
|
||||
tree.split("\0").each do |line|
|
||||
items << parse_tree_line(line)
|
||||
end
|
||||
items
|
||||
end
|
||||
|
||||
# Parses a line of output from the `ls-tree` command.
|
||||
#
|
||||
# line - A String line of output:
|
||||
# "100644 blob 839c2291b30495b9a882c17d08254d3c90d8fb53 Home.md"
|
||||
#
|
||||
# Returns an Array of BlobEntry instances.
|
||||
def parse_tree_line(line)
|
||||
data, name = line.split("\t")
|
||||
mode, type, sha = data.split(' ')
|
||||
name = decode_git_path(name)
|
||||
BlobEntry.new sha, name
|
||||
end
|
||||
|
||||
# Decode octal sequences (\NNN) in tree path names.
|
||||
#
|
||||
# path - String path name.
|
||||
#
|
||||
# Returns a decoded String.
|
||||
def decode_git_path(path)
|
||||
if path[0] == ?" && path[-1] == ?"
|
||||
path = path[1...-1]
|
||||
path.gsub!(/\\\d{3}/) { |m| m[1..-1].to_i(8).chr }
|
||||
end
|
||||
path.gsub!(/\\[rn"\\]/) { |m| eval(%("#{m.to_s}")) }
|
||||
path
|
||||
end
|
||||
|
||||
# Resets the ref and tree caches for this wiki.
|
||||
def clear_cache
|
||||
@ref_map = {}
|
||||
@tree_map = {}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+7
-1
@@ -18,6 +18,12 @@ def testpath(path)
|
||||
File.join(TEST_DIR, path)
|
||||
end
|
||||
|
||||
def commit_details
|
||||
{ :message => "Did something at #{Time.now}",
|
||||
:name => "Tom Preston-Werner",
|
||||
:email => "tom@github.com" }
|
||||
end
|
||||
|
||||
# test/spec/mini 3
|
||||
# http://gist.github.com/25455
|
||||
# chris@ozmm.org
|
||||
@@ -26,7 +32,7 @@ def context(*args, &block)
|
||||
return super unless (name = args.first) && block
|
||||
require 'test/unit'
|
||||
klass = Class.new(defined?(ActiveSupport::TestCase) ? ActiveSupport::TestCase : Test::Unit::TestCase) do
|
||||
def self.test(name, &block)
|
||||
def self.test(name, &block)
|
||||
define_method("test_#{name.gsub(/\W/,'_')}", &block) if block
|
||||
end
|
||||
def self.xtest(*args) end
|
||||
|
||||
+9
-2
@@ -11,8 +11,15 @@ context "File" do
|
||||
end
|
||||
|
||||
test "existing file" do
|
||||
file = @wiki.file("Mordor/todo.txt")
|
||||
commit = @wiki.repo.commits.first
|
||||
file = @wiki.file("Mordor/todo.txt")
|
||||
assert_equal "[ ] Write section on Ents\n", file.raw_data
|
||||
assert_equal @wiki.repo.commits.first.id, file.version.id
|
||||
assert_equal 'todo.txt', file.name
|
||||
assert_equal commit.id, file.version.id
|
||||
assert_equal commit.author.name, file.version.author.name
|
||||
end
|
||||
|
||||
test "accessing tree" do
|
||||
assert_nil @wiki.file("Mordor")
|
||||
end
|
||||
end
|
||||
+107
-23
@@ -6,10 +6,6 @@ context "Markup" do
|
||||
FileUtils.rm_rf(@path)
|
||||
Grit::Repo.init_bare(@path)
|
||||
@wiki = Gollum::Wiki.new(@path)
|
||||
|
||||
@commit = { :message => "Add stuff",
|
||||
:name => "Tom Preston-Werner",
|
||||
:email => "tom@github.com" }
|
||||
end
|
||||
|
||||
teardown do
|
||||
@@ -17,12 +13,18 @@ context "Markup" do
|
||||
end
|
||||
|
||||
test "formats page from Wiki#pages" do
|
||||
@wiki.write_page("Bilbo Baggins", :markdown, "a [[Foo]][[Bar]] b", @commit)
|
||||
@wiki.write_page("Bilbo Baggins", :markdown, "a [[Foo]][[Bar]] b", commit_details)
|
||||
assert @wiki.pages[0].formatted_data
|
||||
end
|
||||
|
||||
#########################################################################
|
||||
#
|
||||
# Links
|
||||
#
|
||||
#########################################################################
|
||||
|
||||
test "double page links no space" do
|
||||
@wiki.write_page("Bilbo Baggins", :markdown, "a [[Foo]][[Bar]] b", @commit)
|
||||
@wiki.write_page("Bilbo Baggins", :markdown, "a [[Foo]][[Bar]] b", commit_details)
|
||||
|
||||
# "<p>a <a class=\"internal absent\" href=\"/Foo\">Foo</a><a class=\"internal absent\" href=\"/Bar\">Bar</a> b</p>"
|
||||
page = @wiki.page("Bilbo Baggins")
|
||||
@@ -41,7 +43,7 @@ context "Markup" do
|
||||
end
|
||||
|
||||
test "double page links with space" do
|
||||
@wiki.write_page("Bilbo Baggins", :markdown, "a [[Foo]] [[Bar]] b", @commit)
|
||||
@wiki.write_page("Bilbo Baggins", :markdown, "a [[Foo]] [[Bar]] b", commit_details)
|
||||
|
||||
# "<p>a <a class=\"internal absent\" href=\"/Foo\">Foo</a> <a class=\"internal absent\" href=\"/Bar\">Bar</a> b</p>"
|
||||
page = @wiki.page("Bilbo Baggins")
|
||||
@@ -60,7 +62,7 @@ context "Markup" do
|
||||
end
|
||||
|
||||
test "page link" do
|
||||
@wiki.write_page("Bilbo Baggins", :markdown, "a [[Bilbo Baggins]] b", @commit)
|
||||
@wiki.write_page("Bilbo Baggins", :markdown, "a [[Bilbo Baggins]] b", commit_details)
|
||||
|
||||
page = @wiki.page("Bilbo Baggins")
|
||||
output = page.formatted_data
|
||||
@@ -69,8 +71,18 @@ context "Markup" do
|
||||
assert_match /\>Bilbo Baggins\</, output
|
||||
end
|
||||
|
||||
test "adds nofollow to links on historical pages" do
|
||||
sha1 = @wiki.write_page("Sauron", :markdown, "a [[b]] c", commit_details)
|
||||
page = @wiki.page("Sauron")
|
||||
sha2 = @wiki.update_page(page, page.name, :markdown, "c [[b]] a", commit_details)
|
||||
regx = /rel="nofollow"/
|
||||
assert_no_match regx, page.formatted_data
|
||||
assert_match regx, @wiki.page(page.name, sha1).formatted_data
|
||||
assert_match regx, @wiki.page(page.name, sha2).formatted_data
|
||||
end
|
||||
|
||||
test "absent page link" do
|
||||
@wiki.write_page("Tolkien", :markdown, "a [[J. R. R. Tolkien]]'s b", @commit)
|
||||
@wiki.write_page("Tolkien", :markdown, "a [[J. R. R. Tolkien]]'s b", commit_details)
|
||||
|
||||
page = @wiki.page("Tolkien")
|
||||
output = page.formatted_data
|
||||
@@ -80,41 +92,76 @@ context "Markup" do
|
||||
end
|
||||
|
||||
test "page link with custom base path" do
|
||||
["/wiki", "/wiki/"].each do |path|
|
||||
["/wiki", "/wiki/"].each_with_index do |path, i|
|
||||
name = "Bilbo Baggins #{i}"
|
||||
@wiki = Gollum::Wiki.new(@path, :base_path => path)
|
||||
@wiki.write_page("Bilbo Baggins", :markdown, "a [[Bilbo Baggins]] b", @commit)
|
||||
@wiki.write_page(name, :markdown, "a [[#{name}]] b", commit_details)
|
||||
|
||||
page = @wiki.page("Bilbo Baggins")
|
||||
page = @wiki.page(name)
|
||||
output = page.formatted_data
|
||||
assert_match /class="internal present"/, output
|
||||
assert_match /href="\/wiki\/Bilbo-Baggins"/, output
|
||||
assert_match /\>Bilbo Baggins\</, output
|
||||
assert_match /class="internal present"/, output
|
||||
assert_match /href="\/wiki\/Bilbo-Baggins-\d"/, output
|
||||
assert_match /\>Bilbo Baggins \d\</, output
|
||||
end
|
||||
end
|
||||
|
||||
test "page link with included #" do
|
||||
@wiki.write_page("Precious #1", :markdown, "a [[Precious #1]] b", commit_details)
|
||||
page = @wiki.page('Precious #1')
|
||||
output = page.formatted_data
|
||||
assert_match /class="internal present"/, output
|
||||
assert_match /href="\/Precious-%231"/, output
|
||||
end
|
||||
|
||||
test "page link with extra #" do
|
||||
@wiki.write_page("Potato", :markdown, "a [[Potato#1]] b", commit_details)
|
||||
page = @wiki.page('Potato')
|
||||
output = page.formatted_data
|
||||
assert_match /class="internal present"/, output
|
||||
assert_match /href="\/Potato#1"/, output
|
||||
end
|
||||
|
||||
test "external page link" do
|
||||
@wiki.write_page("Bilbo Baggins", :markdown, "a [[http://example.com]] b", @commit)
|
||||
@wiki.write_page("Bilbo Baggins", :markdown, "a [[http://example.com]] b", commit_details)
|
||||
|
||||
page = @wiki.page("Bilbo Baggins")
|
||||
assert_equal "<p>a <a href=\"http://example.com\">http://example.com</a> b</p>", page.formatted_data
|
||||
end
|
||||
|
||||
#########################################################################
|
||||
#
|
||||
# Images
|
||||
#
|
||||
#########################################################################
|
||||
|
||||
test "image with http url" do
|
||||
['http', 'https'].each do |scheme|
|
||||
@wiki.write_page("Bilbo Baggins", :markdown, "a [[#{scheme}://example.com/bilbo.jpg]] b", @commit)
|
||||
name = "Bilbo Baggins #{scheme}"
|
||||
@wiki.write_page(name, :markdown, "a [[#{scheme}://example.com/bilbo.jpg]] b", commit_details)
|
||||
|
||||
page = @wiki.page("Bilbo Baggins")
|
||||
page = @wiki.page(name)
|
||||
output = page.formatted_data
|
||||
assert_equal %{<p>a <img src="#{scheme}://example.com/bilbo.jpg" /> b</p>}, output
|
||||
end
|
||||
end
|
||||
|
||||
test "image with extension in caps with http url" do
|
||||
['http', 'https'].each do |scheme|
|
||||
name = "Bilbo Baggins #{scheme}"
|
||||
@wiki.write_page(name, :markdown, "a [[#{scheme}://example.com/bilbo.JPG]] b", commit_details)
|
||||
|
||||
page = @wiki.page(name)
|
||||
output = page.formatted_data
|
||||
assert_equal %{<p>a <img src="#{scheme}://example.com/bilbo.JPG" /> b</p>}, output
|
||||
end
|
||||
end
|
||||
|
||||
test "image with absolute path" do
|
||||
@wiki = Gollum::Wiki.new(@path, :base_path => '/wiki')
|
||||
index = @wiki.repo.index
|
||||
index.add("alpha.jpg", "hi")
|
||||
index.commit("Add alpha.jpg")
|
||||
@wiki.write_page("Bilbo Baggins", :markdown, "a [[/alpha.jpg]] [[a | /alpha.jpg]] b", @commit)
|
||||
@wiki.write_page("Bilbo Baggins", :markdown, "a [[/alpha.jpg]] [[a | /alpha.jpg]] b", commit_details)
|
||||
|
||||
page = @wiki.page("Bilbo Baggins")
|
||||
assert_equal %{<p>a <img src="/wiki/alpha.jpg" /><a href="/wiki/alpha.jpg">a</a> b</p>}, page.formatted_data
|
||||
@@ -203,17 +250,29 @@ context "Markup" do
|
||||
relative_image(content, output)
|
||||
end
|
||||
|
||||
test "absolute image with frame" do
|
||||
content = "a\n\n[[http://example.com/bilbo.jpg|frame]]\n\nb"
|
||||
output = "<p>a</p>\n\n<p><span class=\"frame\"><span><img src=\"http://example.com/bilbo.jpg\" /></span></span></p>\n\n<p>b</p>"
|
||||
relative_image(content, output)
|
||||
end
|
||||
|
||||
test "image with frame and alt" do
|
||||
content = "a\n\n[[alpha.jpg|frame|alt=Alpha]]\n\nb"
|
||||
output = "<p>a</p>\n\n<p><span class=\"frame\"><span><img src=\"/greek/alpha.jpg\" alt=\"Alpha\" /><span>Alpha</span></span></span></p>\n\n<p>b</p>"
|
||||
relative_image(content, output)
|
||||
end
|
||||
|
||||
#########################################################################
|
||||
#
|
||||
# File links
|
||||
#
|
||||
#########################################################################
|
||||
|
||||
test "file link with absolute path" do
|
||||
index = @wiki.repo.index
|
||||
index.add("alpha.jpg", "hi")
|
||||
index.commit("Add alpha.jpg")
|
||||
@wiki.write_page("Bilbo Baggins", :markdown, "a [[Alpha|/alpha.jpg]] b", @commit)
|
||||
@wiki.write_page("Bilbo Baggins", :markdown, "a [[Alpha|/alpha.jpg]] b", commit_details)
|
||||
|
||||
page = @wiki.page("Bilbo Baggins")
|
||||
output = Gollum::Markup.new(page).render
|
||||
@@ -240,6 +299,12 @@ context "Markup" do
|
||||
assert_equal %{<p>a <a href="http://example.com/alpha.jpg">Alpha</a> b</p>}, page.formatted_data
|
||||
end
|
||||
|
||||
#########################################################################
|
||||
#
|
||||
# Code
|
||||
#
|
||||
#########################################################################
|
||||
|
||||
test "code blocks" do
|
||||
content = "a\n\n```ruby\nx = 1\n```\n\nb"
|
||||
output = "<p>a</p>\n\n<div class=\"highlight\"><pre>" +
|
||||
@@ -288,6 +353,12 @@ context "Markup" do
|
||||
compare(content, output)
|
||||
end
|
||||
|
||||
#########################################################################
|
||||
#
|
||||
# Various
|
||||
#
|
||||
#########################################################################
|
||||
|
||||
test "escaped wiki link" do
|
||||
content = "a '[[Foo]], b"
|
||||
output = "<p>a [[Foo]], b</p>"
|
||||
@@ -309,18 +380,30 @@ context "Markup" do
|
||||
compare(content, output, 'org')
|
||||
end
|
||||
|
||||
test "tex block syntax" do
|
||||
#########################################################################
|
||||
#
|
||||
# TeX
|
||||
#
|
||||
#########################################################################
|
||||
|
||||
test "TeX block syntax" do
|
||||
content = 'a \[ a^2 \] b'
|
||||
output = "<p>a <script type=\"math/tex; mode=display\">a^2</script> b</p>"
|
||||
compare(content, output, 'md')
|
||||
end
|
||||
|
||||
test "tex inline syntax" do
|
||||
test "TeX inline syntax" do
|
||||
content = 'a \( a^2 \) b'
|
||||
output = "<p>a <script type=\"math/tex\">a^2</script> b</p>"
|
||||
compare(content, output, 'md')
|
||||
end
|
||||
|
||||
#########################################################################
|
||||
#
|
||||
# Helpers
|
||||
#
|
||||
#########################################################################
|
||||
|
||||
def compare(content, output, ext = "md", regexes = [])
|
||||
index = @wiki.repo.index
|
||||
index.add("Bilbo-Baggins.#{ext}", content)
|
||||
@@ -341,8 +424,9 @@ context "Markup" do
|
||||
index.add("greek/Bilbo-Baggins.md", content)
|
||||
index.commit("Add alpha.jpg")
|
||||
|
||||
@wiki.clear_cache
|
||||
page = @wiki.page("Bilbo Baggins")
|
||||
rendered = Gollum::Markup.new(page).render
|
||||
assert_equal output, rendered
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+7
-1
@@ -1,3 +1,4 @@
|
||||
# ~*~ encoding: utf-8 ~*~
|
||||
require File.join(File.dirname(__FILE__), *%w[helper])
|
||||
|
||||
context "Page" do
|
||||
@@ -109,4 +110,9 @@ context "Page" do
|
||||
footer = @wiki.page("_Footer")
|
||||
assert_nil footer.footer
|
||||
end
|
||||
end
|
||||
|
||||
test "cannot convert non string to human readable page title" do
|
||||
assert_equal '', Gollum::Page.cname(nil)
|
||||
assert_equal '', Gollum::Page.cname(3)
|
||||
end
|
||||
end
|
||||
|
||||
+131
-48
@@ -35,9 +35,54 @@ context "Wiki" do
|
||||
test "list pages" do
|
||||
pages = @wiki.pages
|
||||
assert_equal \
|
||||
%w(Bilbo-Baggins.md Eye-Of-Sauron.md Home.textile My-Precious.md),
|
||||
%w(Bilbo-Baggins.md Eye-Of-Sauron.md Home.textile My-Precious.md),
|
||||
pages.map { |p| p.filename }.sort
|
||||
end
|
||||
|
||||
test "counts pages" do
|
||||
assert_equal 4, @wiki.size
|
||||
end
|
||||
|
||||
test "normalizes commit hash" do
|
||||
commit = {:message => 'abc'}
|
||||
name = @wiki.repo.config['user.name']
|
||||
email = @wiki.repo.config['user.email']
|
||||
assert_equal({:message => 'abc', :name => name, :email => email},
|
||||
@wiki.normalize_commit(commit.dup))
|
||||
|
||||
commit[:name] = 'bob'
|
||||
commit[:email] = ''
|
||||
assert_equal({:message => 'abc', :name => 'bob', :email => email},
|
||||
@wiki.normalize_commit(commit.dup))
|
||||
|
||||
commit[:email] = 'foo@bar.com'
|
||||
assert_equal({:message => 'abc', :name => 'bob', :email => 'foo@bar.com'},
|
||||
@wiki.normalize_commit(commit.dup))
|
||||
end
|
||||
|
||||
test "#tree_map_for caches ref and tree" do
|
||||
assert @wiki.ref_map.empty?
|
||||
assert @wiki.tree_map.empty?
|
||||
@wiki.tree_map_for 'master'
|
||||
assert_equal({"master"=>"60f12f4254f58801b9ee7db7bca5fa8aeefaa56b"}, @wiki.ref_map)
|
||||
|
||||
map = @wiki.tree_map['60f12f4254f58801b9ee7db7bca5fa8aeefaa56b']
|
||||
assert_equal 'Bilbo-Baggins.md', map[0].path
|
||||
assert_equal '', map[0].dir
|
||||
assert_equal map[0].path, map[0].name
|
||||
assert_equal 'Mordor/Eye-Of-Sauron.md', map[3].path
|
||||
assert_equal '/Mordor', map[3].dir
|
||||
assert_equal 'Eye-Of-Sauron.md', map[3].name
|
||||
end
|
||||
|
||||
test "#tree_map_for only caches tree for commit" do
|
||||
assert @wiki.tree_map.empty?
|
||||
@wiki.tree_map_for '60f12f4254f58801b9ee7db7bca5fa8aeefaa56b'
|
||||
assert @wiki.ref_map.empty?
|
||||
|
||||
entry = @wiki.tree_map['60f12f4254f58801b9ee7db7bca5fa8aeefaa56b'][0]
|
||||
assert_equal 'Bilbo-Baggins.md', entry.path
|
||||
end
|
||||
end
|
||||
|
||||
context "Wiki page previewing" do
|
||||
@@ -64,48 +109,48 @@ context "Wiki page writing" do
|
||||
end
|
||||
|
||||
test "write_page" do
|
||||
commit = { :message => "Gollum page",
|
||||
:name => "Tom Preston-Werner",
|
||||
:email => "tom@github.com" }
|
||||
@wiki.write_page("Gollum", :markdown, "# Gollum", commit)
|
||||
cd = commit_details
|
||||
@wiki.write_page("Gollum", :markdown, "# Gollum", cd)
|
||||
assert_equal 1, @wiki.repo.commits.size
|
||||
assert_equal "Gollum page", @wiki.repo.commits.first.message
|
||||
assert_equal "Tom Preston-Werner", @wiki.repo.commits.first.author.name
|
||||
assert_equal "tom@github.com", @wiki.repo.commits.first.author.email
|
||||
assert_equal cd[:message], @wiki.repo.commits.first.message
|
||||
assert_equal cd[:name], @wiki.repo.commits.first.author.name
|
||||
assert_equal cd[:email], @wiki.repo.commits.first.author.email
|
||||
assert @wiki.page("Gollum")
|
||||
|
||||
@wiki.write_page("Bilbo", :markdown, "# Bilbo", commit)
|
||||
@wiki.write_page("Bilbo", :markdown, "# Bilbo", commit_details)
|
||||
assert_equal 2, @wiki.repo.commits.size
|
||||
assert @wiki.page("Bilbo")
|
||||
assert @wiki.page("Gollum")
|
||||
end
|
||||
|
||||
test "is not allowed to overwrite file" do
|
||||
@wiki.write_page("Abc-Def", :markdown, "# Gollum", commit_details)
|
||||
assert_raises Gollum::DuplicatePageError do
|
||||
@wiki.write_page("ABC DEF", :textile, "# Gollum", commit_details)
|
||||
end
|
||||
end
|
||||
|
||||
test "update_page" do
|
||||
commit = { :message => "Gollum page",
|
||||
:name => "Tom Preston-Werner",
|
||||
:email => "tom@github.com" }
|
||||
@wiki.write_page("Gollum", :markdown, "# Gollum", commit)
|
||||
@wiki.write_page("Gollum", :markdown, "# Gollum", commit_details)
|
||||
|
||||
page = @wiki.page("Gollum")
|
||||
@wiki.update_page(page, page.name, :markdown, "# Gollum2", commit)
|
||||
cd = commit_details
|
||||
@wiki.update_page(page, page.name, :markdown, "# Gollum2", cd)
|
||||
|
||||
assert_equal 2, @wiki.repo.commits.size
|
||||
assert_equal "# Gollum2", @wiki.page("Gollum").raw_data
|
||||
assert_equal "Gollum page", @wiki.repo.commits.first.message
|
||||
assert_equal "Tom Preston-Werner", @wiki.repo.commits.first.author.name
|
||||
assert_equal "tom@github.com", @wiki.repo.commits.first.author.email
|
||||
assert_equal cd[:message], @wiki.repo.commits.first.message
|
||||
assert_equal cd[:name], @wiki.repo.commits.first.author.name
|
||||
assert_equal cd[:email], @wiki.repo.commits.first.author.email
|
||||
end
|
||||
|
||||
test "update page with format change" do
|
||||
commit = { :message => "Gollum page",
|
||||
:name => "Tom Preston-Werner",
|
||||
:email => "tom@github.com" }
|
||||
@wiki.write_page("Gollum", :markdown, "# Gollum", commit)
|
||||
@wiki.write_page("Gollum", :markdown, "# Gollum", commit_details)
|
||||
|
||||
assert_equal :markdown, @wiki.page("Gollum").format
|
||||
|
||||
page = @wiki.page("Gollum")
|
||||
@wiki.update_page(page, page.name, :textile, "h1. Gollum", commit)
|
||||
@wiki.update_page(page, page.name, :textile, "h1. Gollum", commit_details)
|
||||
|
||||
assert_equal 2, @wiki.repo.commits.size
|
||||
assert_equal :textile, @wiki.page("Gollum").format
|
||||
@@ -113,30 +158,24 @@ context "Wiki page writing" do
|
||||
end
|
||||
|
||||
test "update page with name change" do
|
||||
commit = { :message => "Gollum page",
|
||||
:name => "Tom Preston-Werner",
|
||||
:email => "tom@github.com" }
|
||||
@wiki.write_page("Gollum", :markdown, "# Gollum", commit)
|
||||
@wiki.write_page("Gollum", :markdown, "# Gollum", commit_details)
|
||||
|
||||
assert_equal :markdown, @wiki.page("Gollum").format
|
||||
|
||||
page = @wiki.page("Gollum")
|
||||
@wiki.update_page(page, 'Smeagol', :markdown, "h1. Gollum", commit)
|
||||
@wiki.update_page(page, 'Smeagol', :markdown, "h1. Gollum", commit_details)
|
||||
|
||||
assert_equal 2, @wiki.repo.commits.size
|
||||
assert_equal "h1. Gollum", @wiki.page("Smeagol").raw_data
|
||||
end
|
||||
|
||||
test "update page with name and format change" do
|
||||
commit = { :message => "Gollum page",
|
||||
:name => "Tom Preston-Werner",
|
||||
:email => "tom@github.com" }
|
||||
@wiki.write_page("Gollum", :markdown, "# Gollum", commit)
|
||||
@wiki.write_page("Gollum", :markdown, "# Gollum", commit_details)
|
||||
|
||||
assert_equal :markdown, @wiki.page("Gollum").format
|
||||
|
||||
page = @wiki.page("Gollum")
|
||||
@wiki.update_page(page, 'Smeagol', :textile, "h1. Gollum", commit)
|
||||
@wiki.update_page(page, 'Smeagol', :textile, "h1. Gollum", commit_details)
|
||||
|
||||
assert_equal 2, @wiki.repo.commits.size
|
||||
assert_equal :textile, @wiki.page("Smeagol").format
|
||||
@@ -144,17 +183,13 @@ context "Wiki page writing" do
|
||||
end
|
||||
|
||||
test "update nested page with format change" do
|
||||
commit = { :message => "Gollum page",
|
||||
:name => "Tom Preston-Werner",
|
||||
:email => "tom@github.com" }
|
||||
|
||||
index = @wiki.repo.index
|
||||
index.add("lotr/Gollum.md", "# Gollum")
|
||||
index.commit("Add nested page")
|
||||
|
||||
page = @wiki.page("Gollum")
|
||||
assert_equal :markdown, @wiki.page("Gollum").format
|
||||
@wiki.update_page(page, page.name, :textile, "h1. Gollum", commit)
|
||||
@wiki.update_page(page, page.name, :textile, "h1. Gollum", commit_details)
|
||||
|
||||
page = @wiki.page("Gollum")
|
||||
assert_equal "lotr/Gollum.textile", page.path
|
||||
@@ -163,23 +198,16 @@ context "Wiki page writing" do
|
||||
end
|
||||
|
||||
test "delete root page" do
|
||||
commit = { :message => "Gollum page",
|
||||
:name => "Tom Preston-Werner",
|
||||
:email => "tom@github.com" }
|
||||
@wiki.write_page("Gollum", :markdown, "# Gollum", commit)
|
||||
@wiki.write_page("Gollum", :markdown, "# Gollum", commit_details)
|
||||
|
||||
page = @wiki.page("Gollum")
|
||||
@wiki.delete_page(page, commit)
|
||||
@wiki.delete_page(page, commit_details)
|
||||
|
||||
assert_equal 2, @wiki.repo.commits.size
|
||||
assert_nil @wiki.page("Gollum")
|
||||
end
|
||||
|
||||
test "delete nested page" do
|
||||
commit = { :message => "Gollum page",
|
||||
:name => "Tom Preston-Werner",
|
||||
:email => "tom@github.com" }
|
||||
|
||||
index = @wiki.repo.index
|
||||
index.add("greek/Bilbo-Baggins.md", "hi")
|
||||
index.add("Gollum.md", "hi")
|
||||
@@ -187,7 +215,7 @@ context "Wiki page writing" do
|
||||
|
||||
page = @wiki.page("Bilbo-Baggins")
|
||||
assert page
|
||||
@wiki.delete_page(page, commit)
|
||||
@wiki.delete_page(page, commit_details)
|
||||
|
||||
assert_equal 2, @wiki.repo.commits.size
|
||||
assert_nil @wiki.page("Bilbo-Baggins")
|
||||
@@ -198,4 +226,59 @@ context "Wiki page writing" do
|
||||
teardown do
|
||||
FileUtils.rm_r(File.join(File.dirname(__FILE__), *%w[examples test.git]))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "Wiki sync with working directory" do
|
||||
setup do
|
||||
@path = testpath('examples/wdtest')
|
||||
Grit::Repo.init(@path)
|
||||
@wiki = Gollum::Wiki.new(@path)
|
||||
end
|
||||
|
||||
test "write a page" do
|
||||
@wiki.write_page("New Page", :markdown, "Hi", commit_details)
|
||||
assert_equal "Hi", File.read(File.join(@path, "New-Page.md"))
|
||||
end
|
||||
|
||||
test "update a page with same name and format" do
|
||||
@wiki.write_page("New Page", :markdown, "Hi", commit_details)
|
||||
page = @wiki.page("New Page")
|
||||
@wiki.update_page(page, page.name, page.format, "Bye", commit_details)
|
||||
assert_equal "Bye", File.read(File.join(@path, "New-Page.md"))
|
||||
end
|
||||
|
||||
test "update a page with different name and same format" do
|
||||
@wiki.write_page("New Page", :markdown, "Hi", commit_details)
|
||||
page = @wiki.page("New Page")
|
||||
@wiki.update_page(page, "New Page 2", page.format, "Bye", commit_details)
|
||||
assert_equal "Bye", File.read(File.join(@path, "New-Page-2.md"))
|
||||
assert !File.exist?(File.join(@path, "New-Page.md"))
|
||||
end
|
||||
|
||||
test "update a page with same name and different format" do
|
||||
@wiki.write_page("New Page", :markdown, "Hi", commit_details)
|
||||
page = @wiki.page("New Page")
|
||||
@wiki.update_page(page, page.name, :textile, "Bye", commit_details)
|
||||
assert_equal "Bye", File.read(File.join(@path, "New-Page.textile"))
|
||||
assert !File.exist?(File.join(@path, "New-Page.md"))
|
||||
end
|
||||
|
||||
test "update a page with different name and different format" do
|
||||
@wiki.write_page("New Page", :markdown, "Hi", commit_details)
|
||||
page = @wiki.page("New Page")
|
||||
@wiki.update_page(page, "New Page 2", :textile, "Bye", commit_details)
|
||||
assert_equal "Bye", File.read(File.join(@path, "New-Page-2.textile"))
|
||||
assert !File.exist?(File.join(@path, "New-Page.md"))
|
||||
end
|
||||
|
||||
test "delete a page" do
|
||||
@wiki.write_page("New Page", :markdown, "Hi", commit_details)
|
||||
page = @wiki.page("New Page")
|
||||
@wiki.delete_page(page, commit_details)
|
||||
assert !File.exist?(File.join(@path, "New-Page.md"))
|
||||
end
|
||||
|
||||
teardown do
|
||||
FileUtils.rm_r(@path)
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user