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

This commit is contained in:
eston
2011-02-28 17:10:51 -08:00
12 changed files with 608 additions and 275 deletions
+3 -2
View File
@@ -23,12 +23,12 @@ Gem::Specification.new do |s|
s.rdoc_options = ["--charset=UTF-8"]
s.extra_rdoc_files = %w[README.md LICENSE]
s.add_dependency('grit', "~> 2.4.0")
s.add_dependency('grit', "~> 2.4.1")
s.add_dependency('github-markup', [">= 0.4.0", "< 1.0.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")
s.add_dependency('sanitize', "~> 2.0.0")
s.add_dependency('nokogiri', "~> 1.4")
s.add_development_dependency('RedCloth')
@@ -37,6 +37,7 @@ Gem::Specification.new do |s|
s.add_development_dependency('rdiscount')
s.add_development_dependency('shoulda')
s.add_development_dependency('rack-test')
s.add_development_dependency('wikicloth')
# = MANIFEST =
s.files = %w[
+1
View File
@@ -12,6 +12,7 @@ require 'gollum/ruby1.8'
# internal
require 'gollum/git_access'
require 'gollum/committer'
require 'gollum/pagination'
require 'gollum/blob_entry'
require 'gollum/wiki'
+217
View File
@@ -0,0 +1,217 @@
module Gollum
# Responsible for handling the commit process for a Wiki. It sets up the
# Git index, provides methods for modifying the tree, and stores callbacks
# to be fired after the commit has been made. This is specifically
# designed to handle multiple updated pages in a single commit.
class Committer
# Gets the instance of the Gollum::Wiki that is being updated.
attr_reader :wiki
# Gets a Hash of commit options.
attr_reader :options
# Initializes the Committer.
#
# wiki - The Gollum::Wiki instance that is being updated.
# options - The commit Hash details:
# :message - The String commit message.
# :name - The String author full name.
# :email - The String email address.
# :parent - Optional Grit::Commit parent to this update.
# :tree - Optional String SHA of the tree to create the
# index from.
# :committer - Optional Gollum::Committer instance. If provided,
# assume that this operation is part of batch of
# updates and the commit happens later.
#
# Returns the Committer instance.
def initialize(wiki, options = {})
@wiki = wiki
@options = options
@callbacks = []
end
# Public: References the Git index for this commit.
#
# Returns a Grit::Index.
def index
@index ||= begin
idx = @wiki.repo.index
if tree = options[:tree]
idx.read_tree(tree)
elsif parent = parents.first
idx.read_tree(parent.tree.id)
end
idx
end
end
# Public: The committer for this commit.
#
# Returns a Grit::Actor.
def actor
@actor ||= begin
@options[:name] = @wiki.default_committer_name if @options[:name].to_s.empty?
@options[:email] = @wiki.default_committer_email if @options[:email].to_s.empty?
Grit::Actor.new(@options[:name], @options[:email])
end
end
# Public: The parent commits to this pending commit.
#
# Returns an array of Grit::Commit instances.
def parents
@parents ||= begin
arr = [@options[:parent] || @wiki.repo.commit('master')]
arr.flatten!
arr.compact!
arr
end
end
# Adds a page to the given Index.
#
# 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(dir, name, format, data, allow_same_ext = false)
path = @wiki.page_file_name(name, format)
dir = '/' if dir.strip.empty?
fullpath = ::File.join(*[@wiki.page_file_dir, dir, path].compact)
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, @wiki.normalize(data))
end
# Update the given file in the repository's working directory if there
# is a working directory present.
#
# 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(dir, name, format)
unless @wiki.repo.bare
if @wiki.page_file_dir
dir = dir.size.zero? ? @wiki.page_file_dir : File.join(dir, @wiki.page_file_dir)
end
path =
if dir == ''
@wiki.page_file_name(name, format)
else
::File.join(dir, @wiki.page_file_name(name, format))
end
Dir.chdir(::File.join(@wiki.repo.path, '..')) do
if file_path_scheduled_for_deletion?(index.tree, path)
@wiki.repo.git.rm({'f' => true}, '--', path)
else
@wiki.repo.git.checkout({}, 'HEAD', '--', path)
end
end
end
end
# Writes the commit to Git and runs the after_commit callbacks.
#
# Returns the String SHA1 of the new commit.
def commit
sha1 = index.commit(@options[:message], parents, actor)
@callbacks.each do |cb|
cb.call(self, sha1)
end
sha1
end
# Adds a callback to be fired after a commit.
#
# block - A block that expects this Committer instance and the created
# commit's SHA1 as the arguments.
#
# Returns nothing.
def after_commit(&block)
@callbacks << block
end
# Determine if a given page (regardless of format) 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.
# path - The String path of the page file. This may include the format
# extension in which case it will be ignored.
#
# Returns the Boolean response.
def page_path_scheduled_for_deletion?(map, path)
parts = path.split('/')
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
end
# 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.
# path - The String path of the file including extension.
#
# 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
end
# Proxies methods t
def method_missing(name, *args)
index.send(name, *args)
end
end
end
+13 -8
View File
@@ -58,11 +58,14 @@ module Precious
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,
committer = Gollum::Committer.new(wiki, commit_message)
commit = {:committer => committer}
update_wiki_page(wiki, page, params[:content], commit, 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]
update_wiki_page(wiki, page.footer, params[:footer], commit) if params[:footer]
update_wiki_page(wiki, page.sidebar, params[:sidebar], commit) if params[:sidebar]
committer.commit
redirect "/#{CGI.escape(Gollum::Page.cname(name))}"
end
@@ -187,10 +190,12 @@ module Precious
end
def update_wiki_page(wiki, page, content, commit_message, name = nil, format = nil)
return if !page || !content || page.raw_data == content
name ||= page.name
format = (format || page.format).to_sym
wiki.update_page(page, name, format, content, commit_message)
return if !page ||
((!content || page.raw_data == content) && page.format == format)
name ||= page.name
format = (format || page.format).to_sym
content ||= page.raw_data
wiki.update_page(page, name, format, content.to_s, commit_message)
end
def commit_message
@@ -0,0 +1,173 @@
/**
* Org-mode Language Definition
**/
(function() {
var OrgMode = {
'function-bold' : {
search: /([^\n]+)([\n\s]*)/g,
replace: "*$1*$2"
},
'function-italic' : {
search: /([^\n]+)([\n\s]*)/g,
replace: "/$1/$2"
},
'function-code' : {
search: /(^[\n]+)([\n\s]*)/g,
replace: "=$1=$2"
},
'function-ul' : {
search: /(.+)([\n]?)/g,
replace: "* $1$2"
},
/* This works, just like it works for Markdown */
'function-ol' : {
search: /(.+)([\n]?)/g,
replace: "1. $1$2"
},
'function-blockquote' : {
search: /(.+)([\n]?)/g,
replace: "#+BEGIN_QUOTE\n$1$2\n#+END_QUOTE\n"
},
'function-h1' : {
search: /(.+)([\n]?)/g,
replace: "* $1$2"
},
'function-h2' : {
search: /(.+)([\n]?)/g,
replace: "** $1$2"
},
'function-h3' : {
search: /(.+)([\n]?)/g,
replace: "*** $1$2"
},
'function-link' : {
exec: function( txt, selText, $field ) {
var results = null;
$.GollumEditor.Dialog.init({
title: 'Insert Link',
fields: [
{
id: 'text',
name: 'Link Text',
type: 'text'
},
{
id: 'href',
name: 'URL',
type: 'text'
}
],
OK: function( res ) {
var rep = '';
if ( res['text'] && res['href'] ) {
rep = '[[' + res['href'] + ']['
+ res['text'] + ']]';
}
else if ( res['href'] ) {
rep = '[[' + res['href'] + ']]';
}
$.GollumEditor.replaceSelection( rep );
}
});
}
},
'function-image' : {
exec: function( txt, selText, $field ) {
var results = null;
$.GollumEditor.Dialog.init({
title: 'Insert Image',
fields: [
{
id: 'url',
name: 'Image URL',
type: 'text'
},
],
OK: function( res ) {
var rep = '';
if ( res['url'] ) {
rep = '[[' + res['url'] + ']]';
}
$.GollumEditor.replaceSelection( rep );
}
});
}
}
};
var OrgModeHelp = [
{
menuName: 'Block Elements',
content: [
{
menuName: 'Paragraphs &amp; Breaks',
data: '<p>To create a paragraph, simply create a block of text that is not separated by one or more blank lines. Blocks of text separated by one or more blank lines will be parsed as paragraphs.</p>'
},
{
menuName: 'Headers',
data: '<p>Simply prefix your header text with the number of <code>*</code> characters to specify heading depth. For example: <code>* Header 1</code>, <code>** Header 2</code> and <code>*** Header 3</code> will be progressively smaller headers.</p>'
},
{
menuName: 'Blockquotes',
data: '<p>To create a blockquote, simple embed the text between <code>#+BEGIN_QUOTE</code> and <code>#+END_QUOTE</code>. An example quote block is displayed below:<br><code>#+BEGIN_QUOTE<br>This is my quote block. Quote something nice here, otherwise there is no point in quoting.<br>#+END_QUOTE</code></p>'
},
{
menuName: 'Lists',
data: '<p>Org-mode supports both ordered and unordered lists. To create an ordered list, simply prefix each line with a number (any number will do &mdash; this is why the editor only uses one number.) To create an unordered list, you can prefix each line with <code>+</code> or <code>-</code>.</p>'
},
{
menuName: 'Code Blocks',
data: '<p>Code Blocks are similar to blockquote, except that <code>#+BEGIN_EXAMPLE</code> and <code>#+END_EXAMPLE</code> are used.</p>'
},
{
menuName: 'Tables',
data: '<p>Org-mode supports simple tables (tables with equal number of cells in each row). To create a simple table, just separate the contents of each cell with a <code>|</code> character. For example, <br><br><code>|one|two|three|<br>|four|five|six|</code><br><br> will appear as a table with two rows and three columns. Additionally, <br><br><code>|one|two|three|<br>|---+---+-----|<br>|four|five|six|</code><br><br> will also appear as a table, but the first row will be interpreted as a header row and the <code>&lt;th&gt;</code> tag will be used to render it. </p>'
},
]
},
{
menuName: 'Span Elements',
content: [
{
menuName: 'Links',
data: '<p>To create links to external pages, you need to enclose the URI in double square brackets. (i.e., <code>[[http://github.com/]]</code> will automatically be parsed to <a href="javascript:void(0);">http://github.com/</a>)If you want to add text, to be displayed to the user, you write the URI and the text next to each other, both enclosed in square brackets and both of them together enclosed in another pair of square brackets. For example, if you want your link to display the text &ldquo;GitHub&rdquo;, you write <code>[[http://github.com][GitHub]]</code>.</p>'
},
{
menuName: 'Emphasis',
data: '<p>Forward slashes (<code>/</code>) are treated as emphasis and are wrapped with an <code>&lt;i&gt;</code> tag. Asterisks (<code>*</code>) are treated as bold using the <code>&lt;b&gt;</code> tag.</p>'
},
{
menuName: 'Code',
data: '<p>To create inline spans of code, simply wrap the code in equal signs (<code>=</code>). Orgmode will turn <code>=myFunction=</code> into <code>myFunction</code>.</p>'
},
{
menuName: 'Images',
data: "<p>Org-mode image syntax is exactly same as the syntax that you would use for a URI to link to itself. The image URI is enclosed in double square brackets. Alt text on images is not currently supported by Gollum's Org-mode parser.</p>"
}
]
},
];
jQuery.GollumEditor.defineLanguage('org', OrgMode);
jQuery.GollumEditor.defineHelp('org', OrgModeHelp);
})();
+1 -1
View File
@@ -221,7 +221,7 @@ module Gollum
# Returns an Array of BlobEntry instances.
def parse_tree_line(line)
mode, type, sha, size, *name = line.split(/\s+/)
BlobEntry.new(sha, name.to_s, size.to_i)
BlobEntry.new(sha, name.join(' '), size.to_i)
end
# Decode octal sequences (\NNN) in tree path names.
+3 -3
View File
@@ -136,7 +136,7 @@ module Gollum
Sanitize.clean(header.to_html)
else
Sanitize.clean(name)
end
end.strip
end
# Public: The path of the page within the repo.
@@ -333,9 +333,9 @@ module Gollum
# path - The String directory path of the page file.
#
# Returns the populated Gollum::Page.
def populate(blob, path)
def populate(blob, path=nil)
@blob = blob
@path = (path + '/' + blob.name)[1..-1]
@path = "#{path}/#{blob.name}"[1..-1]
self
end
+117 -238
View File
@@ -168,10 +168,10 @@ module Gollum
def preview_page(name, data, format)
page = @page_class.new(self)
ext = @page_class.format_to_ext(format.to_sym)
path = @page_class.cname(name) + '.' + ext
blob = OpenStruct.new(:name => path, :data => data)
page.populate(blob, path)
page.version = @access.commit('HEAD')
name = @page_class.cname(name) + '.' + ext
blob = OpenStruct.new(:name => name, :data => data)
page.populate(blob)
page.version = @access.commit('master')
page
end
@@ -181,22 +181,36 @@ module Gollum
# format - The Symbol format of the page.
# data - The new String contents of the page.
# commit - The commit Hash details:
# :message - The String commit message.
# :name - The String author full name.
# :email - The String email address.
# :message - The String commit message.
# :name - The String author full name.
# :email - The String email address.
# :parent - Optional Grit::Commit parent to this update.
# :tree - Optional String SHA of the tree to create the
# index from.
# :committer - Optional Gollum::Committer instance. If provided,
# assume that this operation is part of batch of
# updates and the commit happens later.
#
# Returns the String SHA1 of the newly written version.
# Returns the String SHA1 of the newly written version, or the
# Gollum::Committer instance if this is part of a batch update.
def write_page(name, format, data, commit = {})
index = nil
sha1 = commit_index(commit) do |idx|
index = idx
add_to_index(index, '', name, format, data)
multi_commit = false
committer = if obj = commit[:committer]
multi_commit = true
obj
else
Committer.new(self, commit)
end
@access.refresh
update_working_dir(index, '', name, format)
committer.add_to_index('', name, format, data)
sha1
committer.after_commit do |index, sha|
@access.refresh
index.update_working_dir('', name, format)
end
multi_commit ? committer : committer.commit
end
# Public: Update an existing page with new content. The location of the
@@ -209,57 +223,85 @@ module Gollum
# format - The Symbol format of the page.
# data - The new String contents of the page.
# commit - The commit Hash details:
# :message - The String commit message.
# :name - The String author full name.
# :email - The String email address.
# :message - The String commit message.
# :name - The String author full name.
# :email - The String email address.
# :parent - Optional Grit::Commit parent to this update.
# :tree - Optional String SHA of the tree to create the
# index from.
# :committer - Optional Gollum::Committer instance. If provided,
# assume that this operation is part of batch of
# updates and the commit happens later.
#
# Returns the String SHA1 of the newly written version.
# Returns the String SHA1 of the newly written version, or the
# Gollum::Committer instance if this is part of a batch update.
def update_page(page, name, format, data, commit = {})
name ||= page.name
format ||= page.format
dir = ::File.dirname(page.path)
dir = '' if dir == '.'
index = nil
sha1 = commit_index(commit) do |idx|
index = idx
if page.name == name && page.format == format
index.add(page.path, normalize(data))
else
index.delete(page.path)
add_to_index(index, dir, name, format, data, :allow_same_ext)
end
multi_commit = false
committer = if obj = commit[:committer]
multi_commit = true
obj
else
Committer.new(self, commit)
end
@access.refresh
update_working_dir(index, dir, page.name, page.format)
update_working_dir(index, dir, name, format)
if page.name == name && page.format == format
committer.add(page.path, normalize(data))
else
committer.delete(page.path)
committer.add_to_index(dir, name, format, data, :allow_same_ext)
end
sha1
committer.after_commit do |index, sha|
@access.refresh
index.update_working_dir(dir, page.name, page.format)
index.update_working_dir(dir, name, format)
end
multi_commit ? committer : committer.commit
end
# Public: Delete a page.
#
# page - The Gollum::Page to delete.
# commit - The commit Hash details:
# :message - The String commit message.
# :name - The String author full name.
# :email - The String email address.
# :message - The String commit message.
# :name - The String author full name.
# :email - The String email address.
# :parent - Optional Grit::Commit parent to this update.
# :tree - Optional String SHA of the tree to create the
# index from.
# :committer - Optional Gollum::Committer instance. If provided,
# assume that this operation is part of batch of
# updates and the commit happens later.
#
# Returns the String SHA1 of the newly written version.
# Returns the String SHA1 of the newly written version, or the
# Gollum::Committer instance if this is part of a batch update.
def delete_page(page, commit)
index = nil
sha1 = commit_index(commit) do |idx|
index = idx
index.delete(page.path)
multi_commit = false
committer = if obj = commit[:committer]
multi_commit = true
obj
else
Committer.new(self, commit)
end
committer.delete(page.path)
committer.after_commit do |index, sha|
dir = ::File.dirname(page.path)
dir = '' if dir == '.'
@access.refresh
index.update_working_dir(dir, page.name, page.format)
end
dir = ::File.dirname(page.path)
dir = '' if dir == '.'
@access.refresh
update_working_dir(index, dir, page.name, page.format)
sha1
multi_commit ? committer : committer.commit
end
# Public: Applies a reverse diff for a given page. If only 1 SHA is given,
@@ -274,6 +316,7 @@ module Gollum
# :message - The String commit message.
# :name - The String author full name.
# :email - The String email address.
# :parent - Optional Grit::Commit parent to this update.
#
# Returns a String SHA1 of the new commit, or nil if the reverse diff does
# not apply.
@@ -283,41 +326,39 @@ module Gollum
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]
patch = full_reverse_diff_for(page, sha1, sha2)
committer = Committer.new(self, commit)
parent = committer.parents[0]
committer.options[:tree] = @repo.git.apply_patch(parent.sha, patch)
return false unless committer.options[:tree]
committer.after_commit do |index, sha|
@access.refresh
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]
files = []
if page
files << [page.path, page.name, page.format]
else
# Grit::Diff can't parse reverse diffs.... yet
patch.each_line do |line|
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 == '.'
index.update_working_dir(dir, name, format)
end
end
files.each do |(path, name, format)|
dir = ::File.dirname(path)
dir = '' if dir == '.'
update_working_dir(index, dir, name, format)
end
sha1
committer.commit
end
# Public: Applies a reverse diff to the repo. If only 1 SHA is given,
@@ -464,38 +505,6 @@ module Gollum
@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
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)
else
@repo.git.checkout({}, 'HEAD', '--', path)
end
end
end
end
# Fill an array with a list of pages.
#
# ref - A String ref that is either a commit SHA or references one.
@@ -510,122 +519,6 @@ module Gollum
end
end
# 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.
# path - The String path of the file including extension.
#
# 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
end
# Determine if a given page (regardless of format) 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.
# path - The String path of the page file. This may include the format
# extension in which case it will be ignored.
#
# Returns the Boolean response.
def page_path_scheduled_for_deletion?(map, path)
parts = path.split('/')
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
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(*[@page_file_dir, dir, path].compact)
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
# 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')]
parents.flatten!
parents.compact!
index = self.repo.index
if tree = options[:tree]
index.read_tree(tree)
elsif parent = parents[0]
index.read_tree(parent.tree.id)
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.
@@ -654,20 +547,6 @@ module Gollum
full_reverse_diff_for(nil, sha1, sha2)
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.
#
# Returns the String name.
+9 -6
View File
@@ -30,14 +30,15 @@ context "Frontend" do
end
test "edits page footer and sidebar" do
page_1 = @wiki.page('A')
foot_1 = page_1.footer
side_1 = page_1.sidebar
commits = @wiki.repo.commits('master').size
page_1 = @wiki.page('A')
foot_1 = page_1.footer
side_1 = page_1.sidebar
post "/edit/A",
:footer => 'footer', :sidebar => 'sidebar',
:format => page_1.format, :message => 'def'
:footer => 'footer', :page => "A", :sidebar => 'sidebar', :message => 'def'
follow_redirect!
assert_equal "/A", last_request.fullpath
assert last_response.ok?
@wiki.clear_cache
@@ -53,6 +54,7 @@ context "Frontend" do
assert_equal 'sidebar', side_2.raw_data
assert_equal 'def', side_2.version.message
assert_not_equal side_1.version.sha, side_2.version.sha
assert_equal commits+1, @wiki.repo.commits('master').size
end
test "renames page" do
@@ -61,6 +63,7 @@ context "Frontend" do
:rename => "C",
:format => page_1.format, :message => 'def'
follow_redirect!
assert_equal "/C", last_request.fullpath
assert last_response.ok?
@wiki.clear_cache
@@ -138,4 +141,4 @@ context "Frontend" do
def app
Precious::App
end
end
end
+50
View File
@@ -0,0 +1,50 @@
require File.expand_path(File.join(File.dirname(__FILE__), "helper"))
context "Wiki" do
setup do
@wiki = Gollum::Wiki.new(testpath("examples/lotr.git"))
end
test "normalizes commit hash" do
commit = {:message => 'abc'}
name = @wiki.repo.config['user.name']
email = @wiki.repo.config['user.email']
committer = Gollum::Committer.new(@wiki, commit)
assert_equal name, committer.actor.name
assert_equal email, committer.actor.email
commit[:name] = 'bob'
commit[:email] = ''
committer = Gollum::Committer.new(@wiki, commit)
assert_equal 'bob', committer.actor.name
assert_equal email, committer.actor.email
commit[:email] = 'foo@bar.com'
committer = Gollum::Committer.new(@wiki, commit)
assert_equal 'bob', committer.actor.name
assert_equal 'foo@bar.com', committer.actor.email
end
test "yield after_commit callback" do
@path = cloned_testpath('examples/lotr.git')
yielded = nil
begin
wiki = Gollum::Wiki.new(@path)
committer = Gollum::Committer.new(wiki)
committer.after_commit do |index, sha1|
yielded = sha1
assert_equal committer, index
end
res = wiki.write_page("Gollum", :markdown, "# Gollum",
:committer => committer)
assert_equal committer, res
sha1 = committer.commit
assert_equal sha1, yielded
ensure
FileUtils.rm_rf(@path)
end
end
end
+21
View File
@@ -238,6 +238,27 @@ context "Markup" do
assert_equal %{<p>a <img src="/wiki/greek/alpha.jpg" /><a href="/wiki/greek/alpha.jpg">a</a> b</p>}, output
end
test "image with absolute path on a preview" do
@wiki = Gollum::Wiki.new(@path, :base_path => '/wiki')
index = @wiki.repo.index
index.add("alpha.jpg", "hi")
index.commit("Add alpha.jpg")
page = @wiki.preview_page("Test", "a [[/alpha.jpg]] b", :markdown)
assert_equal %{<p>a <img src="/wiki/alpha.jpg" /> b</p>}, page.formatted_data
end
test "image with relative path on a preview" do
@wiki = Gollum::Wiki.new(@path, :base_path => '/wiki')
index = @wiki.repo.index
index.add("alpha.jpg", "hi")
index.add("greek/alpha.jpg", "hi")
index.commit("Add alpha.jpg")
page = @wiki.preview_page("Test", "a [[alpha.jpg]] [[greek/alpha.jpg]] b", :markdown)
assert_equal %{<p>a <img src="/wiki/alpha.jpg" /><img src="/wiki/greek/alpha.jpg" /> b</p>}, page.formatted_data
end
test "image with alt" do
content = "a [[alpha.jpg|alt=Alpha Dog]] b"
output = %{<p>a <img src="/greek/alpha.jpg" alt="Alpha Dog" /> b</p>}
-17
View File
@@ -44,23 +44,6 @@ context "Wiki" 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 "text_data" do
wiki = Gollum::Wiki.new(testpath("examples/yubiwa.git"))
if String.instance_methods.include?(:encoding)