Permalink
Browse files

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

  • Loading branch information...
2 parents 049d9d6 + e1f92e3 commit 56bd0b9757308636e98c28af6ea10ba5409567cc eston committed Jan 19, 2011
View
7 HISTORY.md
@@ -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
View
25 README.md
@@ -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.
View
21 bin/gollum
@@ -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,24 +73,24 @@ 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
end
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
View
4 gollum.gemspec
@@ -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")
View
9 lib/gollum/albino.rb
@@ -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
View
26 lib/gollum/frontend/app.rb
@@ -44,7 +44,7 @@ class App < Sinatra::Base
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 @@ class App < Sinatra::Base
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 @@ class App < Sinatra::Base
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 @@ class App < Sinatra::Base
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 @@ class App < Sinatra::Base
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 @@ class App < Sinatra::Base
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 @@ class App < Sinatra::Base
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 @@ class App < Sinatra::Base
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 @@ class App < Sinatra::Base
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
View
29 lib/gollum/git_access.rb
@@ -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 @@ def exist?
@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 @@ def ref_to_sha(ref)
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 @@ def ref_to_sha!(ref)
#
# 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 @@ def set_cache(name, key, value)
# 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)
View
90 lib/gollum/markup.rb
@@ -13,6 +13,7 @@ def initialize(page)
@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 @@ def initialize(page)
#
# 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 @@ def extract_tags(data)
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 @@ def extract_tags(data)
# 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 @@ def process_tag(tag, no_follow = false)
# 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 @@ def parse_image_tag_options(tag)
# 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 @@ def process_file_link_tag(tag, no_follow = false)
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 @@ def process_page_link_tag(tag, no_follow = false)
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 @@ def find_file(name)
#
# 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 @@ def find_page_from_name(cname)
#
# 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 @@ def extract_code(data)
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 @@ def process_code(data)
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.
View
59 lib/gollum/page.rb
@@ -41,6 +41,40 @@ def self.valid_page_name?(filename)
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 @@ def formatted_data(&block)
# [ :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.
View
211 lib/gollum/wiki.rb
@@ -59,7 +59,7 @@ def markup_class
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 @@ def sanitization
@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,33 +94,38 @@ def history_sanitization
# 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 = {})
if path.is_a?(GitAccess)
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 @@ def delete_page(page, commit)
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 @@ def pages(treeish = nil)
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 @@ def size(ref = nil)
#
# 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 @@ def log(options = {})
@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 @@ def clear_cache
@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 @@ def sanitizer
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 @@ def page_file_name(name, format)
# 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 @@ def add_to_index(index, dir, name, format, data, allow_same_ext = false)
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 @@ def add_to_index(index, dir, name, format, data, allow_same_ext = false)
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 @@ def commit_index(options = {})
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 @@ def normalize_commit(commit = {})
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
View
1 test/examples/page_file_dir.git/COMMIT_EDITMSG
@@ -0,0 +1 @@
+initial commit
View
1 test/examples/page_file_dir.git/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
View
6 test/examples/page_file_dir.git/config
@@ -0,0 +1,6 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ ignorecase = true
View
1 test/examples/page_file_dir.git/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
View
BIN test/examples/page_file_dir.git/index
Binary file not shown.
View
6 test/examples/page_file_dir.git/info/exclude
@@ -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]
+# *~
View
1 test/examples/page_file_dir.git/logs/HEAD
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 22b404803c966dd92865614d86ff22ca12e50c1e rick <technoweenie@gmail.com> 1295287591 -0800 commit (initial): initial commit
View
1 test/examples/page_file_dir.git/logs/refs/heads/master
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 22b404803c966dd92865614d86ff22ca12e50c1e rick <technoweenie@gmail.com> 1295287591 -0800 commit (initial): initial commit
View
BIN test/examples/page_file_dir.git/objects/0c/7d27db1f575263efdcab3dc650f4502a2dbcbf
Binary file not shown.
View
BIN test/examples/page_file_dir.git/objects/22/b404803c966dd92865614d86ff22ca12e50c1e
Binary file not shown.
View
BIN test/examples/page_file_dir.git/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99
Binary file not shown.
View
BIN test/examples/page_file_dir.git/objects/57/16ca5987cbf97d6bb54920bea6adde242d87e6
Binary file not shown.
View
BIN test/examples/page_file_dir.git/objects/5b/43e14e0a15fb6f08feab1773d1c0991e9f71e2
Binary file not shown.
View
1 test/examples/page_file_dir.git/refs/heads/master
@@ -0,0 +1 @@
+22b404803c966dd92865614d86ff22ca12e50c1e
View
5 test/test_app.rb
@@ -8,6 +8,7 @@
@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 @@
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 @@
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!
View
52 test/test_markup.rb
@@ -162,6 +162,20 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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
View
17 test/test_page_revert.rb
@@ -12,19 +12,30 @@
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
View
70 test/test_wiki.rb
@@ -61,30 +61,6 @@
@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 @@
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 @@
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

0 comments on commit 56bd0b9

Please sign in to comment.