Merge branch 'master' of github.com:github/gollum

This commit is contained in:
eston
2011-01-18 22:59:51 -08:00
28 changed files with 451 additions and 192 deletions
+5 -2
View File
@@ -2,15 +2,18 @@
* Major Enhancements
* Add Page sidebars, similar to Page footers.
* Add the ability to revert commits to the wiki.
* Add MediaWiki support.
* Minor Enhancements
* Add `:sanitization` and `:history_sanitization` options for customizing
* Add `:sanitization` and `:history_sanitization` options for customizing
how `Sanitize.clean` modifies formatted wiki content.
* Add `--config` option for the command line, to specify a ruby file that is
run during startup.
* Provide access to a parsed Nokogiri::DocumentFragment during markup
* Provide access to a parsed Nokogiri::DocumentFragment during markup
rendering for added customization.
* Bug Fixes
* Use `@wiki.page_class` in Gollum::Markup where appropriate (#63).
* Fix parsing of Org mode file links (#87).
# 1.1.0 / 2010-10-28
+18 -7
View File
@@ -9,7 +9,7 @@ Gollum wikis are simply Git repositories that adhere to a specific format.
Gollum pages may be written in a variety of formats and can be edited in a
number of ways depending on your needs. You can edit your wiki locally:
* With your favorite text editor or IDE.
* With your favorite text editor or IDE (changes will be visible after committing).
* With the built-in web interface.
* With the Gollum Ruby API.
@@ -35,6 +35,7 @@ to install the dependencies for the formats that you plan to use.
* [RDoc](http://rdoc.sourceforge.net/)
* [ReStructuredText](http://docutils.sourceforge.net/rst.html) -- `easy_install docutils`
* [Textile](http://www.textism.com/tools/textile/) -- `gem install RedCloth`
* [MediaWiki](http://www.mediawiki.org/wiki/Help:Formatting) -- `gem install wikicloth`
## RUNNING
@@ -74,6 +75,7 @@ current list of formats and allowed extensions is:
* RDoc: .rdoc
* ReStructuredText: .rest.txt, .rst.txt, .rest, .rst
* Textile: .textile
* MediaWiki: .mediawiki, .wiki
Gollum detects the page file format via the extension, so files must have one
of the supported extensions in order to be converted.
@@ -90,13 +92,19 @@ The special page file `Home.ext` (where the extension is one of the supported
formats) will be used as the entrance page to your wiki. If it is missing, an
automatically generated table of contents will be shown instead.
## SIDEBAR FILES
Sidebar files allow you to add a simple sidebar to your wiki. Sidebar files
are named `_Sidebar.ext` where the extension is one of the supported formats.
Sidebars affect all pages in their directory and any subdirectories that do not
have a sidebar file of their own.
## FOOTER FILES
Footer files allow you to add a simple footer to your wiki. Footer files must
be named `_Footer.ext` where the extension is one of the supported formats.
Footers affect all pages in their directory and any subdirectories that do not
have a footer file of their own.
Like sidebars, footers affect all pages in their directory and any
subdirectories that do not have a footer file of their own.
## HTML SANITIZATION
@@ -124,6 +132,9 @@ the link text displayed on the page. If the tag is an embedded image, the
first thing in the tag will be a path to an image file. Use this trick to
easily remember which order things should appear in tags.
Some formats, such as MediaWiki, support the opposite syntax:
[[Page Title|Link]]
## PAGE LINKS
@@ -210,7 +221,7 @@ the pipe.
## IMAGES
To display images that are contained in the Gollum repository you should use
the Gollum Image Tag. This will display the actual image on the page.
the Gollum Image Tag. This will display the actual image on the page.
[[gollum.png]]
@@ -268,8 +279,8 @@ This is useful for writing about the link syntax in your wiki pages.
## SYNTAX HIGHLIGHTING
In page files you can get automatic syntax highlighting for a wide range of
languages (courtesy of [Pygments](http://pygments.org/)) by using the
following syntax:
languages (courtesy of [Pygments](http://pygments.org/) - must install
separately) by using the following syntax:
```ruby
def foo
@@ -432,4 +443,4 @@ your changes merged back into core is as follows:
1. Do not change the version number, I will do that on my end
1. If necessary, rebase your commits into logical chunks, without errors
1. Push the branch up to GitHub
1. Send me (mojombo) a pull request for your branch
1. Send a pull request to the github/gollum project.
+15 -6
View File
@@ -19,6 +19,8 @@ require 'gollum'
exec = {}
options = { 'port' => 4567, 'bind' => '0.0.0.0' }
wiki_options = {}
opts = OptionParser.new do |opts|
opts.banner = help
@@ -42,6 +44,10 @@ opts = OptionParser.new do |opts|
opts.on("--irb", "Start an irb process with gollum loaded for the current wiki.") do
options['irb'] = true
end
opts.on("--page-file-dir [PATH]", "Specify the sub directory for all page files (default: repository root).") do |path|
wiki_options[:page_file_dir] = path
end
end
# Read command line options into `options` hash
@@ -67,13 +73,13 @@ if options['irb']
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
@@ -81,10 +87,10 @@ if options['irb']
end
begin
wiki = Gollum::Wiki.new(gollum_path)
wiki = Gollum::Wiki.new(gollum_path, wiki_options)
if !wiki.exist? then raise Grit::InvalidGitRepositoryError end
puts "Loaded Gollum wiki at #{File.expand_path(gollum_path).inspect}."
puts
puts
puts %( page = wiki.page('page-name'))
puts %( # => <Gollum::Page>)
puts
@@ -103,11 +109,14 @@ if options['irb']
else
require 'gollum/frontend/app'
Precious::App.set(:gollum_path, gollum_path)
Precious::App.set(:wiki_options, wiki_options)
if cfg = options['config']
# If the path begins with a '/' it will be considered an absolute path,
# otherwise it will be relative to the CWD
cfg = File.join(Dir.getwd, cfg) unless cfg.slice(0) == File::SEPARATOR
cfg = File.join(Dir.getwd, cfg) unless cfg.slice(0) == File::SEPARATOR
require cfg
end
Precious::App.run!(options)
end
+2 -2
View File
@@ -23,9 +23,9 @@ Gem::Specification.new do |s|
s.rdoc_options = ["--charset=UTF-8"]
s.extra_rdoc_files = %w[README.md LICENSE]
s.add_dependency('grit', "~> 2.3")
s.add_dependency('grit', "~> 2.4.0")
s.add_dependency('github-markup', [">= 0.4.0", "< 1.0.0"])
s.add_dependency('albino', "~> 1.0")
s.add_dependency('albino', "~> 1.2.3")
s.add_dependency('sinatra', "~> 1.0")
s.add_dependency('mustache', [">= 0.11.2", "< 1.0.0"])
s.add_dependency('sanitize', "~> 1.1")
+2 -7
View File
@@ -1,13 +1,8 @@
require 'albino'
class Gollum::Albino < Albino
def self.bin
Albino.bin
end
def bin
Albino.bin
end
self.bin = ::Albino.bin
self.default_encoding = ::Albino.default_encoding
def colorize(options = {})
html = super.to_s
+15 -11
View File
@@ -44,7 +44,7 @@ module Precious
get '/edit/*' do
@name = params[:splat].first
wiki = Gollum::Wiki.new(settings.gollum_path)
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
if page = wiki.page(@name)
@page = page
@content = page.raw_data
@@ -55,11 +55,11 @@ module Precious
end
post '/edit/*' do
wiki = Gollum::Wiki.new(settings.gollum_path)
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
page = wiki.page(params[:splat].first)
name = params[:rename] || page.name
msg = commit_message
update_wiki_page(wiki, page, params[:content], msg, name,
update_wiki_page(wiki, page, params[:content], msg, name,
params[:format])
update_wiki_page(wiki, page.footer, params[:footer], msg) if params[:footer]
update_wiki_page(wiki, page.sidebar, params[:sidebar], msg) if params[:sidebar]
@@ -69,7 +69,7 @@ module Precious
post '/create' do
name = params[:page]
wiki = Gollum::Wiki.new(settings.gollum_path)
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
format = params[:format].intern
@@ -83,7 +83,7 @@ module Precious
end
post '/revert/:page/*' do
wiki = Gollum::Wiki.new(settings.gollum_path)
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
@name = params[:page]
@page = wiki.page(@name)
shas = params[:splat].first.split("/")
@@ -103,7 +103,7 @@ module Precious
end
post '/preview' do
wiki = Gollum::Wiki.new(settings.gollum_path)
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
@name = "Preview"
@page = wiki.preview_page(@name, params[:content], params[:format])
@content = @page.formatted_data
@@ -112,7 +112,7 @@ module Precious
get '/history/:name' do
@name = params[:name]
wiki = Gollum::Wiki.new(settings.gollum_path)
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
@page = wiki.page(@name)
@page_num = [params[:page].to_i, 1].max
@versions = @page.versions :page => @page_num
@@ -134,16 +134,20 @@ module Precious
get '/compare/:name/:version_list' do
@name = params[:name]
@versions = params[:version_list].split(/\.{2,3}/)
wiki = Gollum::Wiki.new(settings.gollum_path)
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
@page = wiki.page(@name)
diffs = wiki.repo.diff(@versions.first, @versions.last, @page.path)
@diff = diffs.first
mustache :compare
end
get %r{^/(javascript|css|images)} do
halt 404
end
get %r{/(.+?)/([0-9a-f]{40})} do
name = params[:captures][0]
wiki = Gollum::Wiki.new(settings.gollum_path)
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
if page = wiki.page(name, params[:captures][1])
@page = page
@name = name
@@ -156,7 +160,7 @@ module Precious
get '/search' do
@query = params[:q]
wiki = Gollum::Wiki.new(settings.gollum_path)
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
@results = wiki.search @query
@name = @query
mustache :search
@@ -167,7 +171,7 @@ module Precious
end
def show_page_or_file(name)
wiki = Gollum::Wiki.new(settings.gollum_path)
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
if page = wiki.page(name)
@page = page
@name = name
+22 -7
View File
@@ -2,7 +2,15 @@ module Gollum
# Controls all access to the Git objects from Gollum. Extend this class to
# add custom caching for special cases.
class GitAccess
def initialize(path)
# Initializes the GitAccess instance.
#
# path - The String path to the Git repository that holds the
# Gollum site.
# page_file_dir - String the directory in which all page files reside
#
# Returns this instance.
def initialize(path, page_file_dir = nil)
@page_file_dir = page_file_dir
@path = path
@repo = Grit::Repo.new(path)
clear
@@ -15,7 +23,7 @@ module Gollum
@repo.git.exist?
end
# Public: Converts a given Git reference to a SHA, using the cache if
# Public: Converts a given Git reference to a SHA, using the cache if
# available.
#
# ref - a String Git reference (ex: "master")
@@ -29,7 +37,7 @@ module Gollum
end
end
# Public: Gets a recursive list of Git blobs for the whole tree at the
# Public: Gets a recursive list of Git blobs for the whole tree at the
# given commit.
#
# ref - A String Git reference or Git SHA to a commit.
@@ -144,10 +152,17 @@ module Gollum
#
# Returns an Array of BlobEntry instances.
def tree!(sha)
tree = @repo.git.native(:ls_tree,
tree = @repo.git.native(:ls_tree,
{:r => true, :l => true, :z => true}, sha)
tree.split("\0").inject([]) do |items, line|
items << parse_tree_line(line)
items = tree.split("\0").inject([]) do |memo, line|
memo << parse_tree_line(line)
end
if dir = @page_file_dir
regex = /^#{dir}\//
items.select { |i| i.path =~ regex }
else
items
end
end
@@ -201,7 +216,7 @@ module Gollum
# Parses a line of output from the `ls-tree` command.
#
# line - A String line of output:
# "100644 blob 839c2291b30495b9a882c17d08254d3c90d8fb53 Home.md"
# "100644 blob 839c2291b30495b9a882c17d08254d3c90d8fb53 Home.md"
#
# Returns an Array of BlobEntry instances.
def parse_tree_line(line)
+50 -40
View File
@@ -13,6 +13,7 @@ module Gollum
@name = page.filename
@data = page.text_data
@version = page.version.id
@format = page.format
@dir = ::File.dirname(page.path)
@tagmap = {}
@codemap = {}
@@ -28,8 +29,8 @@ module Gollum
#
# Returns the formatted String content.
def render(no_follow = false)
sanitize = no_follow ?
@wiki.history_sanitizer :
sanitize = no_follow ?
@wiki.history_sanitizer :
@wiki.sanitizer
data = extract_tex(@data.dup)
@@ -120,7 +121,18 @@ module Gollum
if $1 == "'" && $3 != "'"
"[[#{$2}]]#{$3}"
elsif $2.include?('][')
$&
if $2[0..4] == 'file:'
pre = $1
post = $3
parts = $2.split('][')
parts[0][0..4] = ""
link = "#{parts[1]}|#{parts[0].sub(/\.org/,'')}"
id = Digest::SHA1.hexdigest(link)
@tagmap[id] = link
"#{pre}#{id}#{post}"
else
$&
end
else
id = Digest::SHA1.hexdigest($2)
@tagmap[id] = $2
@@ -134,32 +146,28 @@ module Gollum
# final markup.
#
# 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, no_follow = false)
def process_tags(data)
@tagmap.each do |id, tag|
data.gsub!(id, process_tag(tag, no_follow))
data.gsub!(id, process_tag(tag))
end
data
end
# Process a single tag into its final HTML form.
#
# tag - The String tag contents (the stuff inside the double
# 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, no_follow = false)
def process_tag(tag)
if html = process_image_tag(tag)
html
elsif html = process_file_link_tag(tag, no_follow)
elsif html = process_file_link_tag(tag)
html
else
process_page_link_tag(tag, no_follow)
process_page_link_tag(tag)
end
end
@@ -171,6 +179,8 @@ module Gollum
# if it is not.
def process_image_tag(tag)
parts = tag.split('|')
return if parts.size.zero?
name = parts[0].strip
path = if file = find_file(name)
::File.join @wiki.base_path, file.path
@@ -252,15 +262,15 @@ module Gollum
# Attempt to process the tag as a file link tag.
#
# tag - The String tag contents (the stuff inside the double
# 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, no_follow = false)
def process_file_link_tag(tag)
parts = tag.split('|')
return if parts.size.zero?
name = parts[0].strip
path = parts[1] && parts[1].strip
path = if path && file = find_file(path)
@@ -271,33 +281,30 @@ module Gollum
nil
end
tag = if name && path && file
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
# 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, no_follow = false)
def process_page_link_tag(tag)
parts = tag.split('|')
name = parts[0].strip
cname = @wiki.page_class.cname((parts[1] || parts[0]).strip)
tag = if name =~ %r{^https?://} && parts[1].nil?
parts.reverse! if @format == :mediawiki
name, page_name = *parts.compact.map(&:strip)
cname = @wiki.page_class.cname(page_name || name)
if name =~ %r{^https?://} && page_name.nil?
%{<a href="#{name}">#{name}</a>}
else
presence = "absent"
@@ -310,10 +317,6 @@ module Gollum
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.
@@ -335,7 +338,7 @@ module Gollum
#
# cname - The String canonical page name.
#
# Returns a Gollum::Page instance if a page is found, or an Array of
# 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)
@@ -359,11 +362,11 @@ module Gollum
#
# Returns the placeholder'd String data.
def extract_code(data)
data.gsub!(/^``` ?(.+?)\r?\n(.+?)\r?\n```\r?$/m) do
data.gsub!(/^``` ?([^\r\n]+)?\r?\n(.+?)\r?\n```\r?$/m) do
id = Digest::SHA1.hexdigest($2)
cached = check_cache(:code, id)
@codemap[id] = cached ?
{ :output => cached } :
@codemap[id] = cached ?
{ :output => cached } :
{ :lang => $1, :code => $2 }
id
end
@@ -379,12 +382,19 @@ module Gollum
def process_code(data)
@codemap.each do |id, spec|
formatted = spec[:output] || begin
lang = spec[:lang]
code = spec[:code]
lang = spec[:lang]
if code.lines.all? { |line| line =~ /\A\r?\n\Z/ || line =~ /^( |\t)/ }
code.gsub!(/^( |\t)/m, '')
end
formatted = Gollum::Albino.new(code, lang).colorize
formatted = begin
lang && Gollum::Albino.colorize(code, lang)
rescue ::Albino::ShellArgumentError, ::Albino::Process::TimeoutExceeded,
::Albino::Process::MaximumOutputExceeded
end
formatted ||= "<pre><code>#{CGI.escapeHTML(code)}</code></pre>"
update_cache(:code, id, formatted)
formatted
end
@@ -393,7 +403,7 @@ module Gollum
data
end
# Hook for getting the formatted value of extracted tag data.
# Hook for getting the formatted value of extracted tag data.
#
# type - Symbol value identifying what type of data is being extracted.
# id - String SHA1 hash of original extracted tag data.
+35 -24
View File
@@ -41,6 +41,40 @@ module Gollum
filename =~ /^_/ ? false : match
end
# Public: The format of a given filename.
#
# filename - The String filename.
#
# Returns the Symbol format of the page. One of:
# [ :markdown | :textile | :rdoc | :org | :rest | :asciidoc | :pod |
# :roff ]
def self.format_for(filename)
case filename.to_s
when /\.(md|mkdn?|mdown|markdown)$/i
:markdown
when /\.(textile)$/i
:textile
when /\.(rdoc)$/i
:rdoc
when /\.(org)$/i
:org
when /\.(creole)$/i
:creole
when /\.(re?st(\.txt)?)$/i
:rest
when /\.(asciidoc)$/i
:asciidoc
when /\.(pod)$/i
:pod
when /\.(\d)$/i
:roff
when /\.(media)?wiki$/i
:mediawiki
else
nil
end
end
# Reusable filter to turn a filename (without path) into a canonical name.
# Strips extension, converts spaces to dashes.
#
@@ -143,30 +177,7 @@ module Gollum
# [ :markdown | :textile | :rdoc | :org | :rest | :asciidoc | :pod |
# :roff ]
def format
case @blob.name
when /\.(md|mkdn?|mdown|markdown)$/i
:markdown
when /\.(textile)$/i
:textile
when /\.(rdoc)$/i
:rdoc
when /\.(org)$/i
:org
when /\.(creole)$/i
:creole
when /\.(re?st(\.txt)?)$/i
:rest
when /\.(asciidoc)$/i
:asciidoc
when /\.(pod)$/i
:pod
when /\.(\d)$/i
:roff
when /\.(media)?wiki$/i
:mediawiki
else
nil
end
self.class.format_for(@blob.name)
end
# Public: The current version of the page.
+158 -53
View File
@@ -59,7 +59,7 @@ module Gollum
end
end
# Gets the default sanitization options for current pages used by
# Gets the default sanitization options for current pages used by
# instances of this Wiki.
def sanitization
if @sanitization.nil?
@@ -68,7 +68,7 @@ module Gollum
@sanitization
end
# Gets the default sanitization options for older page revisions used by
# Gets the default sanitization options for older page revisions used by
# instances of this Wiki.
def history_sanitization
if @history_sanitization.nil?
@@ -94,17 +94,21 @@ module Gollum
# Gets the sanitization options for older page revisions used by this Wiki.
attr_reader :history_sanitization
# Gets the String directory in which all page files reside.
attr_reader :page_file_dir
# Public: Initialize a new Gollum Repo.
#
# repo - The String path to the Git repository that holds the Gollum
# path - The String path to the Git repository that holds the Gollum
# site.
# options - Optional Hash:
# :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
# :markup_class - The markup Class. Default: Gollum::Markup
# :sanitization - An instance of Sanitization.
# :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
# :markup_class - The markup Class. Default: Gollum::Markup
# :sanitization - An instance of Sanitization.
# :page_file_dir - String the directory in which all page files reside
#
# Returns a fresh Gollum::Repo.
def initialize(path, options = {})
@@ -112,15 +116,16 @@ module Gollum
options[:access] = path
path = path.path
end
@path = path
@access = options[:access] || GitAccess.new(path)
@base_path = options[:base_path] || "/"
@page_class = options[:page_class] || self.class.page_class
@file_class = options[:file_class] || self.class.file_class
@markup_class = options[:markup_class] || self.class.markup_class
@repo = @access.repo
@sanitization = options[:sanitization] || self.class.sanitization
@history_sanitization = options[:history_sanitization] ||
@path = path
@page_file_dir = options[:page_file_dir]
@access = options[:access] || GitAccess.new(path, @page_file_dir)
@base_path = options[:base_path] || "/"
@page_class = options[:page_class] || self.class.page_class
@file_class = options[:file_class] || self.class.file_class
@markup_class = options[:markup_class] || self.class.markup_class
@repo = @access.repo
@sanitization = options[:sanitization] || self.class.sanitization
@history_sanitization = options[:history_sanitization] ||
self.class.history_sanitization
end
@@ -257,6 +262,82 @@ module Gollum
sha1
end
# Public: Applies a reverse diff for a given page. If only 1 SHA is given,
# the reverse diff will be taken from its parent (^SHA...SHA). If two SHAs
# are given, the reverse diff is taken from SHA1...SHA2.
#
# page - The Gollum::Page to delete.
# sha1 - String SHA1 of the earlier parent if two SHAs are given,
# or the child.
# sha2 - Optional String SHA1 of the child.
# commit - The commit Hash details:
# :message - The String commit message.
# :name - The String author full name.
# :email - The String email address.
#
# Returns a String SHA1 of the new commit, or nil if the reverse diff does
# not apply.
def revert_page(page, sha1, sha2 = nil, commit = {})
if sha2.is_a?(Hash)
commit = sha2
sha2 = nil
end
pcommit = @repo.commit('master')
patch = full_reverse_diff_for(page, sha1, sha2)
commit[:parent] = [pcommit]
commit[:tree] = @repo.git.apply_patch(pcommit.sha, patch)
return false unless commit[:tree]
index = nil
sha1 = commit_index(commit) { |i| index = i }
@access.refresh
files = []
if page
files << [page.path, page.name, page.format]
else
# Grit::Diff can't parse reverse diffs.... yet
lines = patch.split("\n")
while line = lines.shift
if line =~ %r{^diff --git b/.+? a/(.+)$}
path = $1
ext = ::File.extname(path)
name = ::File.basename(path, ext)
if format = ::Gollum::Page.format_for(ext)
files << [path, name, format]
end
end
end
end
files.each do |(path, name, format)|
dir = ::File.dirname(path)
dir = '' if dir == '.'
update_working_dir(index, dir, name, format)
end
sha1
end
# Public: Applies a reverse diff to the repo. If only 1 SHA is given,
# the reverse diff will be taken from its parent (^SHA...SHA). If two SHAs
# are given, the reverse diff is taken from SHA1...SHA2.
#
# sha1 - String SHA1 of the earlier parent if two SHAs are given,
# or the child.
# sha2 - Optional String SHA1 of the child.
# commit - The commit Hash details:
# :message - The String commit message.
# :name - The String author full name.
# :email - The String email address.
#
# Returns a String SHA1 of the new commit, or nil if the reverse diff does
# not apply.
def revert_commit(sha1, sha2 = nil, commit = {})
revert_page(nil, sha1, sha2, commit)
end
# Public: Lists all pages for this wiki.
#
# treeish - The String commit ID or ref to find (default: master)
@@ -266,7 +347,7 @@ module Gollum
tree_list(treeish || 'master')
end
# Public: Returns the number of pages accessible from a commit
# Public: Returns the number of pages accessible from a commit
#
# ref - A String ref that is either a commit SHA or references one.
#
@@ -285,10 +366,10 @@ module Gollum
#
# 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')
args = [{:c => query}, 'master', '--']
args << '--' << @page_file_dir if @page_file_dir
search_output.split("\n").collect do |line|
@repo.git.grep(*args).split("\n").map! do |line|
result = line.split(':')
file_name = Gollum::Page.canonicalize_filename(::File.basename(result[1]))
@@ -310,28 +391,6 @@ module Gollum
@repo.log('master', nil, log_pagination_options(options))
end
def revert_page(page, sha1, sha2 = nil, commit = {})
if sha2.is_a?(Hash)
commit = sha2
sha2 = nil
end
pcommit = @repo.commit('master')
patch = full_reverse_diff_for(page, sha1, sha2)
commit[:parent] = [pcommit]
commit[:tree] = @repo.git.apply_patch(pcommit.sha, patch)
return false unless commit[:tree]
index = nil
sha1 = commit_index(commit) { |i| index = i }
dir = ::File.dirname(page.path)
dir = '' if dir == '.'
@access.refresh
update_working_dir(index, dir, page.name, page.format)
sha1
end
# Public: Refreshes just the cached Git reference data. This should
# be called after every Gollum update.
#
@@ -340,7 +399,7 @@ module Gollum
@access.refresh
end
# Public: Creates a Sanitize instance using the Wiki's sanitization
# Public: Creates a Sanitize instance using the Wiki's sanitization
# options.
#
# Returns a Sanitize instance.
@@ -350,7 +409,7 @@ module Gollum
end
end
# Public: Creates a Sanitize instance using the Wiki's history sanitization
# Public: Creates a Sanitize instance using the Wiki's history sanitization
# options.
#
# Returns a Sanitize instance.
@@ -416,13 +475,17 @@ module Gollum
# 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))
if @page_file_dir
dir = dir.size.zero? ? @page_file_dir : File.join(dir, @page_file_dir)
end
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)
@@ -517,7 +580,7 @@ module Gollum
dir = '/' if dir.strip.empty?
fullpath = ::File.join(dir, path)
fullpath = ::File.join(*[@page_file_dir, dir, path].compact)
fullpath = fullpath[1..-1] if fullpath =~ /^\//
if index.current_tree && tree = index.current_tree / dir
@@ -536,6 +599,14 @@ module Gollum
index.add(fullpath, normalize(data))
end
# Commits to the repo. This is a common method used by Gollum for
# creating, updating, and deleting pages. There are typically three steps:
# building an index with the current tree, yielding the index for
# modification, and then writing the commit.
#
# options - Hash of option
#
# Returns the String SHA of the new Commit.
def commit_index(options = {})
normalize_commit(options)
parents = [options[:parent] || @repo.commit('master')]
@@ -549,13 +620,38 @@ module Gollum
end
yield index if block_given?
options[:name] = default_committer_name if options[:name].to_s.empty?
options[:email] = default_committer_email if options[:email].to_s.empty?
actor = Grit::Actor.new(options[:name], options[:email])
index.commit(options[:message], parents, actor)
end
# Creates a reverse diff for the given SHAs on the given Gollum::Page.
#
# page - The Gollum::Page to scope the patch to, or a String Path.
# sha1 - String SHA1 of the earlier parent if two SHAs are given,
# or the child.
# sha2 - Optional String SHA1 of the child.
#
# Returns a String of the reverse Diff to apply.
def full_reverse_diff_for(page, sha1, sha2 = nil)
sha1, sha2 = "#{sha1}^", sha1 if sha2.nil?
repo.git.native(:diff, {:R => true}, sha1, sha2, '--', page.path)
args = [{:R => true}, sha1, sha2]
if page
args << '--' << (page.respond_to?(:path) ? page.path : page.to_s)
end
repo.git.native(:diff, *args)
end
# Creates a reverse diff for the given SHAs.
#
# sha1 - String SHA1 of the earlier parent if two SHAs are given,
# or the child.
# sha2 - Optional String SHA1 of the child.
#
# Returns a String of the reverse Diff to apply.
def full_reverse_diff(sha1, sha2 = nil)
full_reverse_diff_for(nil, sha1, sha2)
end
# Ensures a commit hash has all the required fields for a commit.
@@ -573,17 +669,26 @@ module Gollum
end
# Gets the default name for commits.
#
# Returns the String name.
def default_committer_name
@default_committer_name ||= \
@repo.config['user.name'] || self.class.default_committer_name
end
# Gets the default email for commits.
#
# Returns the String email address.
def default_committer_email
@default_committer_email ||= \
@repo.config['user.email'] || self.class.default_committer_email
end
# Gets the commit object for the given ref or sha.
#
# ref - A string ref or SHA pointing to a valid commit.
#
# Returns a Grit::Commit instance.
def commit_for(ref)
@access.commit(ref)
rescue Grit::GitRuby::Repository::NoSuchShaFound
@@ -0,0 +1 @@
initial commit
+1
View File
@@ -0,0 +1 @@
ref: refs/heads/master
+6
View File
@@ -0,0 +1,6 @@
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
@@ -0,0 +1 @@
Unnamed repository; edit this file 'description' to name the repository.
Binary file not shown.
@@ -0,0 +1,6 @@
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
@@ -0,0 +1 @@
0000000000000000000000000000000000000000 22b404803c966dd92865614d86ff22ca12e50c1e rick <technoweenie@gmail.com> 1295287591 -0800 commit (initial): initial commit
@@ -0,0 +1 @@
0000000000000000000000000000000000000000 22b404803c966dd92865614d86ff22ca12e50c1e rick <technoweenie@gmail.com> 1295287591 -0800 commit (initial): initial commit
@@ -0,0 +1 @@
22b404803c966dd92865614d86ff22ca12e50c1e
+3 -2
View File
@@ -8,6 +8,7 @@ context "Frontend" do
@path = cloned_testpath("examples/revert.git")
@wiki = Gollum::Wiki.new(@path)
Precious::App.set(:gollum_path, @path)
Precious::App.set(:wiki_options, {})
end
teardown do
@@ -16,7 +17,7 @@ context "Frontend" do
test "edits page" do
page_1 = @wiki.page('A')
post "/edit/A", :content => 'abc',
post "/edit/A", :content => 'abc',
:format => page_1.format, :message => 'def'
follow_redirect!
assert last_response.ok?
@@ -56,7 +57,7 @@ context "Frontend" do
test "renames page" do
page_1 = @wiki.page('B')
post "/edit/B", :content => 'abc',
post "/edit/B", :content => 'abc',
:rename => "C",
:format => page_1.format, :message => 'def'
follow_redirect!
+48 -4
View File
@@ -162,6 +162,20 @@ context "Markup" do
assert_equal "<p>a <a href=\"http://example.com\">http://example.com</a> b</p>", page.formatted_data
end
test "page link with different text" do
@wiki.write_page("Potato", :markdown, "a [[Potato Heaad|Potato]] ", commit_details)
page = @wiki.page("Potato")
output = page.formatted_data
assert_equal "<p>a <a class=\"internal present\" href=\"/Potato\">Potato Heaad</a></p>", output
end
test "page link with different text on mediawiki" do
@wiki.write_page("Potato", :mediawiki, "a [[Potato|Potato Heaad]] ", commit_details)
page = @wiki.page("Potato")
output = page.formatted_data
assert_equal "<p>\na <a class=\"internal present\" href=\"/Potato\">Potato Heaad</a> \n</p>", output
end
#########################################################################
#
# Images
@@ -343,7 +357,7 @@ context "Markup" do
content = "a\n\n```ruby\nx = 1\n```\n\nb"
output = "<p>a</p>\n\n<div class=\"highlight\"><pre>" +
"<span class=\"n\">x</span> <span class=\"o\">=</span> " +
"<span class=\"mi\">1</span>\n</pre>\n</div>\n\n<p>b</p>"
"<span class=\"mi\">1</span>\n</pre>\n</div>\n\n\n<p>b</p>"
index = @wiki.repo.index
index.add("Bilbo-Baggins.md", content)
@@ -358,7 +372,7 @@ context "Markup" do
content = "a\r\n\r\n```ruby\r\nx = 1\r\n```\r\n\r\nb"
output = "<p>a</p>\n\n<div class=\"highlight\"><pre>" +
"<span class=\"n\">x</span> <span class=\"o\">=</span> " +
"<span class=\"mi\">1</span>\n</pre>\n</div>\n\n<p>b</p>"
"<span class=\"mi\">1</span>\n</pre>\n</div>\n\n\n<p>b</p>"
index = @wiki.repo.index
index.add("Bilbo-Baggins.md", content)
@@ -374,7 +388,7 @@ context "Markup" do
output = "<p>a</p>\n\n<div class=\"highlight\"><pre><span class=\"n\">" +
"x</span> <span class=\"o\">=</span> <span class=\"mi\">1" +
"</span>\n\n<span class=\"n\">y</span> <span class=\"o\">=" +
"</span> <span class=\"mi\">2</span>\n</pre>\n</div>\n\n<p>b</p>"
"</span> <span class=\"mi\">2</span>\n</pre>\n</div>\n\n\n<p>b</p>"
compare(content, output)
end
@@ -383,7 +397,19 @@ context "Markup" do
output = "<p>a</p>\n\n<div class=\"highlight\"><pre><span class=\"n\">" +
"x</span> <span class=\"o\">=</span> <span class=\"mi\">1" +
"</span>\n\n<span class=\"n\">y</span> <span class=\"o\">=" +
"</span> <span class=\"mi\">2</span>\n</pre>\n</div>\n\n<p>b</p>"
"</span> <span class=\"mi\">2</span>\n</pre>\n</div>\n\n\n<p>b</p>"
compare(content, output)
end
test "code block with invalid lang" do
content = "a\n\n``` ls -al;\n\tbooya\n\tboom\n```\n\nb"
output = "<p>a</p>\n\n<pre><code>booya\nboom</code></pre>\n\n<p>b</p>"
compare(content, output)
end
test "code block with no lang" do
content = "a\n\n```\n\tls -al;\n\t<booya>\n```\n\nb"
output = "<p>a</p>\n\n<pre><code>ls -al;\n&lt;booya&gt;</code></pre>\n\n<p>b</p>"
compare(content, output)
end
@@ -414,6 +440,24 @@ context "Markup" do
compare(content, output, 'org')
end
test "org mode style double file links" do
content = "a [[file:f.org][Google]] b"
output = "<p class=\"title\">a <a class=\"internal absent\" href=\"/f\">Google</a> b</p>"
compare(content, output, 'org')
end
test "short double links" do
content = "a [[b]] c"
output = %(<p class="title">a <a class="internal absent" href="/b">b</a> c</p>)
compare(content, output, 'org')
end
test "double linked pipe" do
content = "a [[|]] b"
output = %(<p class="title">a <a class="internal absent" href="/"></a> b</p>)
compare(content, output, 'org')
end
#########################################################################
#
# TeX
+14 -3
View File
@@ -12,19 +12,30 @@ context "Page Reverting" do
end
test "reverts single commit" do
page1 = @wiki.page("B")
sha = @wiki.revert_commit('7c45b5f16ff3bae2a0063191ef832701214d4df5')
page2 = @wiki.page("B")
assert_equal sha, page2.version.sha
assert_equal "INITIAL", body=page2.raw_data.strip
assert_equal body, File.read(File.join(@path, "B.md")).strip
end
test "reverts single commit for a page" do
page1 = @wiki.page('B')
sha = @wiki.revert_page(page1, '7c45b5f16ff3bae2a0063191ef832701214d4df5')
page2 = @wiki.page('B')
assert_equal sha, page2.version.sha
assert_equal "INITIAL", page2.raw_data.strip
assert_equal "INITIAL", body=page2.raw_data.strip
assert_equal body, File.read(File.join(@path, "B.md")).strip
end
test "reverts multiple commits" do
test "reverts multiple commits for a page" do
page1 = @wiki.page('A')
sha = @wiki.revert_page(page1, '302a5491a9a5ba12c7652ac831a44961afa312d2^', 'b26b791cb7917c4f37dd9cb4d1e0efb24ac4d26f')
page2 = @wiki.page('A')
assert_equal sha, page2.version.sha
assert_equal "INITIAL", page2.raw_data.strip
assert_equal "INITIAL", body=page2.raw_data.strip
assert_equal body, File.read(File.join(@path, "A.md")).strip
end
test "cannot revert conflicting commit" do
+46 -24
View File
@@ -61,30 +61,6 @@ context "Wiki" do
@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
test "text_data" do
wiki = Gollum::Wiki.new(testpath("examples/yubiwa.git"))
if String.instance_methods.include?(:encoding)
@@ -97,6 +73,19 @@ context "Wiki" do
assert_equal page.raw_data, page.text_data
end
end
test "gets reverse diff" do
diff = @wiki.full_reverse_diff('a8ad3c09dd842a3517085bfadd37718856dee813')
assert_match "b/Mordor/_Sidebar.md", diff
assert_match "b/_Sidebar.md", diff
end
test "gets reverse diff for a page" do
diff = @wiki.full_reverse_diff_for('_Sidebar.md', 'a8ad3c09dd842a3517085bfadd37718856dee813')
regex = /b\/Mordor\/\_Sidebar\.md/
assert_match "b/_Sidebar.md", diff
assert_no_match regex, diff
end
end
context "Wiki page previewing" do
@@ -296,3 +285,36 @@ context "Wiki sync with working directory" do
FileUtils.rm_r(@path)
end
end
context "page_file_dir option" do
setup do
@path = cloned_testpath('examples/page_file_dir')
@repo = Grit::Repo.init(@path)
@page_file_dir = 'docs'
@wiki = Gollum::Wiki.new(@path, :page_file_dir => @page_file_dir)
end
test "write a page in sub directory" do
@wiki.write_page("New Page", :markdown, "Hi", commit_details)
assert_equal "Hi", File.read(File.join(@path, @page_file_dir, "New-Page.md"))
assert !File.exist?(File.join(@path, "New-Page.md"))
end
test "a file in page file dir should be found" do
assert @wiki.page("foo")
end
test "a file out of page file dir should not be found" do
assert !@wiki.page("bar")
end
test "search results should be restricted in page filer dir" do
results = @wiki.search("foo")
assert_equal 1, results.size
assert_equal "foo", results[0][:name]
end
teardown do
FileUtils.rm_r(@path)
end
end