Merge branch 'master' into redesign
This commit is contained in:
@@ -5,6 +5,8 @@
|
||||
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
|
||||
rendering for added customization.
|
||||
* Bug Fixes
|
||||
* Use `@wiki.page_class` in Gollum::Markup where appropriate (#63).
|
||||
|
||||
|
||||
@@ -460,6 +460,7 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/frontend/views/layout.rb
|
||||
lib/gollum/frontend/views/page.rb
|
||||
lib/gollum/frontend/views/search.rb
|
||||
lib/gollum/git_access.rb
|
||||
lib/gollum/markup.rb
|
||||
lib/gollum/page.rb
|
||||
lib/gollum/pagination.rb
|
||||
@@ -504,6 +505,7 @@ Gem::Specification.new do |s|
|
||||
test/examples/lotr.git/refs/heads/master
|
||||
test/helper.rb
|
||||
test/test_file.rb
|
||||
test/test_git_access.rb
|
||||
test/test_markup.rb
|
||||
test/test_page.rb
|
||||
test/test_wiki.rb
|
||||
|
||||
@@ -11,6 +11,7 @@ require 'sanitize'
|
||||
require 'gollum/ruby1.8'
|
||||
|
||||
# internal
|
||||
require 'gollum/git_access'
|
||||
require 'gollum/pagination'
|
||||
require 'gollum/blob_entry'
|
||||
require 'gollum/wiki'
|
||||
|
||||
@@ -3,21 +3,25 @@ module Gollum
|
||||
# Gets the String SHA for this blob.
|
||||
attr_reader :sha
|
||||
|
||||
# Gets the String full path for this blob.
|
||||
# Gets the full path String for this blob.
|
||||
attr_reader :path
|
||||
|
||||
def initialize(sha, path)
|
||||
# Gets the Fixnum size of this blob.
|
||||
attr_reader :size
|
||||
|
||||
def initialize(sha, path, size = nil)
|
||||
@sha = sha
|
||||
@path = path
|
||||
@dir = @name = @blob = nil
|
||||
@size = size
|
||||
@dir = @name = @blob = nil
|
||||
end
|
||||
|
||||
# Gets the normalized directory path for this blob.
|
||||
# Gets the normalized directory path String for this blob.
|
||||
def dir
|
||||
@dir ||= self.class.normalize_dir(::File.dirname(@path))
|
||||
end
|
||||
|
||||
# Gets the String file base name for this blob.
|
||||
# Gets the file base name String for this blob.
|
||||
def name
|
||||
@name ||= ::File.basename(@path)
|
||||
end
|
||||
@@ -28,7 +32,8 @@ module Gollum
|
||||
#
|
||||
# Returns an unbaked Grit::Blob instance.
|
||||
def blob(repo)
|
||||
@blob ||= Grit::Blob.create(repo, :id => @sha, :name => @name)
|
||||
@blob ||= Grit::Blob.create(repo,
|
||||
:id => @sha, :name => name, :size => @size)
|
||||
end
|
||||
|
||||
# Gets a Page instance for this blob.
|
||||
|
||||
+2
-3
@@ -53,11 +53,10 @@ module Gollum
|
||||
def find(name, version)
|
||||
checked = name.downcase
|
||||
map = @wiki.tree_map_for(version)
|
||||
sha = @wiki.ref_map[version] || version
|
||||
if entry = map.detect { |entry| entry.path.downcase == checked }
|
||||
@path = name
|
||||
@blob = Grit::Blob.create(@wiki.repo, :id => entry.sha, :name => entry.name)
|
||||
@version = Grit::Commit.create(@wiki.repo, :id => sha)
|
||||
@blob = entry.blob(@wiki.repo)
|
||||
@version = version.is_a?(Grit::Commit) ? version : @wiki.commit_for(version)
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,275 @@
|
||||
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)
|
||||
@path = path
|
||||
@repo = Grit::Repo.new(path)
|
||||
clear
|
||||
end
|
||||
|
||||
# Public: Determines whether the Git repository exists on disk.
|
||||
#
|
||||
# Returns true if it exists, or false.
|
||||
def exist?
|
||||
@repo.git.exist?
|
||||
end
|
||||
|
||||
# Public: Converts a given Git reference to a SHA, using the cache if
|
||||
# available.
|
||||
#
|
||||
# ref - a String Git reference (ex: "master")
|
||||
#
|
||||
# Returns a String.
|
||||
def ref_to_sha(ref)
|
||||
if sha?(ref)
|
||||
ref
|
||||
else
|
||||
get_cache(:ref, ref) { ref_to_sha!(ref) }
|
||||
end
|
||||
end
|
||||
|
||||
# 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.
|
||||
#
|
||||
# Returns an Array of BlobEntry instances.
|
||||
def tree(ref)
|
||||
if sha = ref_to_sha(ref)
|
||||
get_cache(:tree, sha) { tree!(sha) }
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
# Public: Fetches the contents of the Git blob at the given SHA.
|
||||
#
|
||||
# sha - A String Git SHA.
|
||||
#
|
||||
# Returns the String content of the blob.
|
||||
def blob(sha)
|
||||
cat_file!(sha)
|
||||
end
|
||||
|
||||
# Public: Looks up the Git commit using the given Git SHA or ref.
|
||||
#
|
||||
# ref - A String Git SHA or ref.
|
||||
#
|
||||
# Returns a Grit::Commit.
|
||||
def commit(ref)
|
||||
if sha?(ref)
|
||||
get_cache(:commit, ref) { commit!(ref) }
|
||||
else
|
||||
if sha = get_cache(:ref, ref)
|
||||
commit(sha)
|
||||
else
|
||||
if cm = commit!(ref)
|
||||
set_cache(:ref, ref, cm.id)
|
||||
set_cache(:commit, cm.id, cm)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Public: Gets a list of Git commits.
|
||||
#
|
||||
# *shas - An Array of String SHAs.
|
||||
#
|
||||
# Returns an Array of Grit::Commit instances.
|
||||
def commits(*shas)
|
||||
shas.flatten!
|
||||
cached_commits = multi_get(:commit, shas)
|
||||
missing_shas = shas.select do |sha|
|
||||
!cached_commits.key?(sha)
|
||||
end
|
||||
|
||||
multi_commit!(missing_shas, cached_commits) if !missing_shas.empty?
|
||||
|
||||
shas.map { |sha| cached_commits[sha] }
|
||||
end
|
||||
|
||||
# Public: Clears all of the cached data that this GitAccess is tracking.
|
||||
#
|
||||
# Returns nothing.
|
||||
def clear
|
||||
@ref_map = {}
|
||||
@tree_map = {}
|
||||
@commit_map = {}
|
||||
end
|
||||
|
||||
# Public: Refreshes just the cached Git reference data. This should
|
||||
# be called after every Gollum update.
|
||||
#
|
||||
# Returns nothing.
|
||||
def refresh
|
||||
@ref_map.clear
|
||||
end
|
||||
|
||||
#########################################################################
|
||||
#
|
||||
# Internal Methods
|
||||
#
|
||||
#########################################################################
|
||||
|
||||
# Gets the String path to the Git repository.
|
||||
attr_reader :path
|
||||
|
||||
# Gets the Grit::Repo instance for the Git repository.
|
||||
attr_reader :repo
|
||||
|
||||
# Gets a Hash cache of refs to commit SHAs.
|
||||
#
|
||||
# {"master" => "abc123", ...}
|
||||
#
|
||||
attr_reader :ref_map
|
||||
|
||||
# Gets a Hash cache of commit SHAs to a recursive tree of blobs.
|
||||
#
|
||||
# {"abc123" => [<BlobEntry>, <BlobEntry>]}
|
||||
#
|
||||
attr_reader :tree_map
|
||||
|
||||
# Gets a Hash cache of commit SHAs to the Grit::Commit instance.
|
||||
#
|
||||
# {"abcd123" => <Grit::Commit>}
|
||||
#
|
||||
attr_reader :commit_map
|
||||
|
||||
# Raw method for fetching a list of Git commits.
|
||||
#
|
||||
# shas - An Array of String SHAs.
|
||||
# hash - Optional Hash to store the found commits, indexed by their SHA.
|
||||
#
|
||||
# Returns the same Hash instance.
|
||||
def multi_commit!(shas, hash = {})
|
||||
shas.each_slice(500) do |slice|
|
||||
@repo.batch(slice).each do |commit|
|
||||
hash[commit.id] = commit
|
||||
end
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
# Checks to see if the given String is a 40 character hex SHA.
|
||||
#
|
||||
# str - Possible String SHA.
|
||||
#
|
||||
# Returns true if the String is a SHA, or false.
|
||||
def sha?(str)
|
||||
!!(str =~ /^[0-9a-f]{40}$/)
|
||||
end
|
||||
|
||||
# Looks up the Git SHA for the given Git ref.
|
||||
#
|
||||
# ref - String Git ref.
|
||||
#
|
||||
# Returns a String SHA.
|
||||
def ref_to_sha!(ref)
|
||||
@repo.git.rev_list({:max_count=>1}, ref)
|
||||
rescue Grit::GitRuby::Repository::NoSuchShaFound
|
||||
end
|
||||
|
||||
# Looks up the Git blobs for a given commit.
|
||||
#
|
||||
# sha - String commit SHA.
|
||||
#
|
||||
# Returns an Array of BlobEntry instances.
|
||||
def tree!(sha)
|
||||
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)
|
||||
end
|
||||
end
|
||||
|
||||
# Reads the content from the Git db at the given SHA.
|
||||
#
|
||||
# sha - The String SHA.
|
||||
#
|
||||
# Returns the String content of the Git object.
|
||||
def cat_file!(sha)
|
||||
@repo.git.cat_file({:p => true}, sha)
|
||||
end
|
||||
|
||||
# Reads a Git commit.
|
||||
#
|
||||
# sha - The string SHA of the Git commit.
|
||||
#
|
||||
# Returns a Grit::Commit.
|
||||
def commit!(sha)
|
||||
@repo.commit(sha)
|
||||
end
|
||||
|
||||
# Attempts to get the given data from a cache. If it doesn't exist, it'll
|
||||
# pass the results of the yielded block to the cache for future accesses.
|
||||
#
|
||||
# name - The cache prefix used in building the full cache key.
|
||||
# key - The unique cache key suffix, usually a String Git SHA.
|
||||
#
|
||||
# Yields a block to pass to the cache.
|
||||
# Returns the cached result.
|
||||
def get_cache(name, key)
|
||||
cache = instance_variable_get("@#{name}_map")
|
||||
value = cache[key]
|
||||
if value.nil? && block_given?
|
||||
set_cache(name, key, value = yield)
|
||||
end
|
||||
value == :_nil ? nil : value
|
||||
end
|
||||
|
||||
# Writes some data to the internal cache.
|
||||
#
|
||||
# name - The cache prefix used in building the full cache key.
|
||||
# key - The unique cache key suffix, usually a String Git SHA.
|
||||
# value - The value to write to the cache.
|
||||
#
|
||||
# Returns nothing.
|
||||
def set_cache(name, key, value)
|
||||
cache = instance_variable_get("@#{name}_map")
|
||||
cache[key] = value || :_nil
|
||||
end
|
||||
|
||||
# Gets multiple values from the cache in a single call.
|
||||
#
|
||||
# name - The cache prefix used in building the full cache key.
|
||||
# keys - Array of cache key names to fetch.
|
||||
#
|
||||
# Returns a Hash of the objects that were found in the cache, indexed by
|
||||
# the cache key.
|
||||
def multi_get(name, keys)
|
||||
value = instance_variable_get("@#{name}_map")
|
||||
keys.inject({}) do |memo, key|
|
||||
if v = value[key]
|
||||
memo[key] = v
|
||||
end
|
||||
memo
|
||||
end
|
||||
end
|
||||
|
||||
# Parses a line of output from the `ls-tree` command.
|
||||
#
|
||||
# line - A String line of output:
|
||||
# "100644 blob 839c2291b30495b9a882c17d08254d3c90d8fb53 Home.md"
|
||||
#
|
||||
# Returns an Array of BlobEntry instances.
|
||||
def parse_tree_line(line)
|
||||
mode, type, sha, size, *name = line.split(/\s+/)
|
||||
BlobEntry.new(sha, name.to_s, size.to_i)
|
||||
end
|
||||
|
||||
# Decode octal sequences (\NNN) in tree path names.
|
||||
#
|
||||
# path - String path name.
|
||||
#
|
||||
# Returns a decoded String.
|
||||
def decode_git_path(path)
|
||||
if path[0] == ?" && path[-1] == ?"
|
||||
path = path[1...-1]
|
||||
path.gsub!(/\\\d{3}/) { |m| m[1..-1].to_i(8).chr }
|
||||
end
|
||||
path.gsub!(/\\[rn"\\]/) { |m| eval(%("#{m.to_s}")) }
|
||||
path
|
||||
end
|
||||
end
|
||||
end
|
||||
+47
-11
@@ -27,9 +27,9 @@ module Gollum
|
||||
#
|
||||
# Returns the formatted String content.
|
||||
def render(no_follow = false)
|
||||
sanitize_options = no_follow ?
|
||||
@wiki.history_sanitization :
|
||||
@wiki.sanitization
|
||||
sanitize = no_follow ?
|
||||
@wiki.history_sanitizer :
|
||||
@wiki.sanitizer
|
||||
|
||||
data = extract_tex(@data)
|
||||
data = extract_code(data)
|
||||
@@ -44,12 +44,21 @@ module Gollum
|
||||
end
|
||||
data = process_tags(data)
|
||||
data = process_code(data)
|
||||
data = Sanitize.clean(data, sanitize_options.to_hash) if sanitize_options
|
||||
if sanitize || block_given?
|
||||
doc = Nokogiri::HTML::DocumentFragment.parse(data)
|
||||
doc = sanitize.clean_node!(doc) if sanitize
|
||||
yield doc if block_given?
|
||||
data = doc_to_html(doc)
|
||||
end
|
||||
data = process_tex(data)
|
||||
data.gsub!(/<p><\/p>/, '')
|
||||
data
|
||||
end
|
||||
|
||||
def doc_to_html(doc)
|
||||
doc.to_xhtml(:save_with => Nokogiri::XML::Node::SaveOptions::AS_XHTML)
|
||||
end
|
||||
|
||||
#########################################################################
|
||||
#
|
||||
# TeX
|
||||
@@ -349,8 +358,11 @@ module Gollum
|
||||
# Returns the placeholder'd String data.
|
||||
def extract_code(data)
|
||||
data.gsub(/^``` ?(.+?)\r?\n(.+?)\r?\n```\r?$/m) do
|
||||
id = Digest::SHA1.hexdigest($2)
|
||||
@codemap[id] = { :lang => $1, :code => $2 }
|
||||
id = Digest::SHA1.hexdigest($2)
|
||||
cached = check_cache(:code, id)
|
||||
@codemap[id] = cached ?
|
||||
{ :output => cached } :
|
||||
{ :lang => $1, :code => $2 }
|
||||
id
|
||||
end
|
||||
end
|
||||
@@ -363,14 +375,38 @@ module Gollum
|
||||
# Returns the marked up String data.
|
||||
def process_code(data)
|
||||
@codemap.each do |id, spec|
|
||||
lang = spec[:lang]
|
||||
code = spec[:code]
|
||||
if code.lines.all? { |line| line =~ /\A\r?\n\Z/ || line =~ /^( |\t)/ }
|
||||
code.gsub!(/^( |\t)/m, '')
|
||||
formatted = spec[:output] || begin
|
||||
lang = spec[:lang]
|
||||
code = spec[:code]
|
||||
if code.lines.all? { |line| line =~ /\A\r?\n\Z/ || line =~ /^( |\t)/ }
|
||||
code.gsub!(/^( |\t)/m, '')
|
||||
end
|
||||
formatted = Gollum::Albino.new(code, lang).colorize
|
||||
update_cache(:code, id, formatted)
|
||||
formatted
|
||||
end
|
||||
data.gsub!(id, Gollum::Albino.new(code, lang).colorize)
|
||||
data.gsub!(id, formatted)
|
||||
end
|
||||
data
|
||||
end
|
||||
|
||||
# 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.
|
||||
#
|
||||
# Returns the String cached formatted data, or nil.
|
||||
def check_cache(type, id)
|
||||
end
|
||||
|
||||
# Hook for caching 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.
|
||||
# data - The String formatted value to be cached.
|
||||
#
|
||||
# Returns nothing.
|
||||
def update_cache(type, id, data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+31
-20
@@ -132,8 +132,8 @@ module Gollum
|
||||
# Public: The formatted contents of the page.
|
||||
#
|
||||
# Returns the String data.
|
||||
def formatted_data
|
||||
@blob && Gollum::Markup.new(self).render(historical?)
|
||||
def formatted_data(&block)
|
||||
@blob && @wiki.markup_class.new(self).render(historical?, &block)
|
||||
end
|
||||
|
||||
# Public: The format of the page.
|
||||
@@ -196,19 +196,7 @@ module Gollum
|
||||
#
|
||||
# Returns the footer Page or nil if none exists.
|
||||
def footer
|
||||
return nil if page_match('_Footer', self.filename)
|
||||
|
||||
dirs = self.path.split('/')
|
||||
dirs.pop
|
||||
map = @wiki.tree_map_for(self.version.id)
|
||||
while !dirs.empty?
|
||||
if page = find_page_in_tree(map, '_Footer', dirs.join('/'))
|
||||
return page
|
||||
end
|
||||
dirs.pop
|
||||
end
|
||||
|
||||
find_page_in_tree(map, '_Footer', '')
|
||||
find_sub_page :footer
|
||||
end
|
||||
|
||||
# Gets a Boolean determining whether this page is a historical version.
|
||||
@@ -283,11 +271,11 @@ module Gollum
|
||||
#
|
||||
# Returns a Gollum::Page or nil if the page could not be found.
|
||||
def find(name, version)
|
||||
map = @wiki.tree_map_for(version)
|
||||
map = @wiki.tree_map_for(version.to_s)
|
||||
if page = find_page_in_tree(map, name)
|
||||
sha = @wiki.ref_map[version] || version
|
||||
page.version = Grit::Commit.create(@wiki.repo, :id => sha)
|
||||
page.historical = sha == version
|
||||
page.version = version.is_a?(Grit::Commit) ?
|
||||
version : @wiki.commit_for(version)
|
||||
page.historical = page.version.to_s == version.to_s
|
||||
page
|
||||
end
|
||||
rescue Grit::GitRuby::Repository::NoSuchShaFound
|
||||
@@ -302,7 +290,7 @@ module Gollum
|
||||
#
|
||||
# Returns a Gollum::Page or nil if the page could not be found.
|
||||
def find_page_in_tree(map, name, checked_dir = nil)
|
||||
return nil if name.to_s.empty?
|
||||
return nil if !map || name.to_s.empty?
|
||||
if checked_dir = BlobEntry.normalize_dir(checked_dir)
|
||||
checked_dir.downcase!
|
||||
end
|
||||
@@ -356,5 +344,28 @@ module Gollum
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
# Loads a sub page. Sub page nanes (footers) are prefixed with
|
||||
# an underscore to distinguish them from other Pages.
|
||||
#
|
||||
# name - String page name.
|
||||
#
|
||||
# Returns the Page or nil if none exists.
|
||||
def find_sub_page(name)
|
||||
name = "_#{name.to_s.capitalize}"
|
||||
return nil if page_match(name, self.filename)
|
||||
|
||||
dirs = self.path.split('/')
|
||||
dirs.pop
|
||||
map = @wiki.tree_map_for(self.version.id)
|
||||
while !dirs.empty?
|
||||
if page = find_page_in_tree(map, name, dirs.join('/'))
|
||||
return page
|
||||
end
|
||||
dirs.pop
|
||||
end
|
||||
|
||||
find_page_in_tree(map, name, '')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
module Gollum
|
||||
|
||||
# Encapsulate sanitization options.
|
||||
#
|
||||
# This class does not yet support all options of Sanitize library.
|
||||
@@ -104,6 +103,13 @@ module Gollum
|
||||
:allow_comments => allow_comments?
|
||||
}
|
||||
end
|
||||
|
||||
# Builds a Sanitize instance from the current options.
|
||||
#
|
||||
# Returns a Sanitize instance.
|
||||
def to_sanitize
|
||||
Sanitize.new(to_hash)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
+68
-79
@@ -9,6 +9,9 @@ module Gollum
|
||||
# Sets the file class used by all instances of this Wiki.
|
||||
attr_writer :file_class
|
||||
|
||||
# Sets the markup class used by all instances of this Wiki.
|
||||
attr_writer :markup_class
|
||||
|
||||
# Sets the default name for commits.
|
||||
attr_accessor :default_committer_name
|
||||
|
||||
@@ -45,6 +48,17 @@ module Gollum
|
||||
end
|
||||
end
|
||||
|
||||
# Gets the markup class used by all instances of this Wiki.
|
||||
# Default: Gollum::Markup
|
||||
def markup_class
|
||||
@markup_class ||
|
||||
if superclass.respond_to?(:markup_class)
|
||||
superclass.markup_class
|
||||
else
|
||||
::Gollum::Markup
|
||||
end
|
||||
end
|
||||
|
||||
# Gets the default sanitization options for current pages used by
|
||||
# instances of this Wiki.
|
||||
def sanitization
|
||||
@@ -89,27 +103,32 @@ module Gollum
|
||||
# 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.
|
||||
#
|
||||
# Returns a fresh Gollum::Repo.
|
||||
def initialize(path, options = {})
|
||||
if path.is_a?(GitAccess)
|
||||
options[:access] = path
|
||||
path = path.path
|
||||
end
|
||||
@path = path
|
||||
@repo = Grit::Repo.new(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] ||
|
||||
self.class.history_sanitization
|
||||
|
||||
clear_cache
|
||||
end
|
||||
|
||||
# Public: check whether the wiki's git repo exists on the filesystem.
|
||||
#
|
||||
# Returns true if the repo exists, and false if it does not.
|
||||
def exist?
|
||||
@repo.git.exist?
|
||||
@access.exist?
|
||||
end
|
||||
|
||||
# Public: Get the formatted page for a given page name.
|
||||
@@ -147,7 +166,7 @@ module Gollum
|
||||
path = @page_class.cname(name) + '.' + ext
|
||||
blob = OpenStruct.new(:name => path, :data => data)
|
||||
page.populate(blob, path)
|
||||
page.version = self.repo.commit("HEAD")
|
||||
page.version = @access.commit('HEAD')
|
||||
page
|
||||
end
|
||||
|
||||
@@ -176,7 +195,7 @@ module Gollum
|
||||
actor = Grit::Actor.new(commit[:name], commit[:email])
|
||||
sha1 = index.commit(commit[:message], parents, actor)
|
||||
|
||||
@ref_map.clear
|
||||
@access.refresh
|
||||
update_working_dir(index, '', name, format)
|
||||
|
||||
sha1
|
||||
@@ -219,7 +238,7 @@ module Gollum
|
||||
actor = Grit::Actor.new(commit[:name], commit[:email])
|
||||
sha1 = index.commit(commit[:message], [pcommit], actor)
|
||||
|
||||
@ref_map.clear
|
||||
@access.refresh
|
||||
update_working_dir(index, dir, page.name, page.format)
|
||||
update_working_dir(index, dir, name, format)
|
||||
|
||||
@@ -248,7 +267,7 @@ module Gollum
|
||||
actor = Grit::Actor.new(commit[:name], commit[:email])
|
||||
sha1 = index.commit(commit[:message], [pcommit], actor)
|
||||
|
||||
@ref_map.clear
|
||||
@access.refresh
|
||||
update_working_dir(index, dir, page.name, page.format)
|
||||
|
||||
sha1
|
||||
@@ -307,6 +326,34 @@ module Gollum
|
||||
@repo.log('master', nil, log_pagination_options(options))
|
||||
end
|
||||
|
||||
# Public: Refreshes just the cached Git reference data. This should
|
||||
# be called after every Gollum update.
|
||||
#
|
||||
# Returns nothing.
|
||||
def clear_cache
|
||||
@access.refresh
|
||||
end
|
||||
|
||||
# Public: Creates a Sanitize instance using the Wiki's sanitization
|
||||
# options.
|
||||
#
|
||||
# Returns a Sanitize instance.
|
||||
def sanitizer
|
||||
if options = sanitization
|
||||
@sanitizer ||= options.to_sanitize
|
||||
end
|
||||
end
|
||||
|
||||
# Public: Creates a Sanitize instance using the Wiki's history sanitization
|
||||
# options.
|
||||
#
|
||||
# Returns a Sanitize instance.
|
||||
def history_sanitizer
|
||||
if options = history_sanitization
|
||||
@history_sanitizer ||= options.to_sanitize
|
||||
end
|
||||
end
|
||||
|
||||
#########################################################################
|
||||
#
|
||||
# Internal Methods
|
||||
@@ -323,26 +370,15 @@ module Gollum
|
||||
# Returns the String path.
|
||||
attr_reader :path
|
||||
|
||||
# Gets a Hash cache of refs to commit SHAs.
|
||||
#
|
||||
# {"master" => "abc123", ...}
|
||||
#
|
||||
# Returns the Hash cache.
|
||||
attr_reader :ref_map
|
||||
|
||||
# Gets a Hash cache of commit SHAs to a recursive tree of blobs.
|
||||
#
|
||||
# {"abc123" => [["lib/foo.rb", "blob-sha"], [file, sha], ...], ...}
|
||||
#
|
||||
# Returns the Hash cache.
|
||||
attr_reader :tree_map
|
||||
|
||||
# Gets the page class used by all instances of this Wiki.
|
||||
attr_reader :page_class
|
||||
|
||||
# Gets the file class used by all instances of this Wiki.
|
||||
attr_reader :file_class
|
||||
|
||||
# Gets the markup class used by all instances of this Wiki.
|
||||
attr_reader :markup_class
|
||||
|
||||
# Normalize the data.
|
||||
#
|
||||
# data - The String data to be normalized.
|
||||
@@ -397,10 +433,11 @@ module Gollum
|
||||
#
|
||||
# Returns a flat Array of Gollum::Page instances.
|
||||
def tree_list(ref)
|
||||
tree_map_for(ref).inject([]) do |list, entry|
|
||||
sha = @access.ref_to_sha(ref)
|
||||
commit = @access.commit(sha)
|
||||
tree_map_for(sha).inject([]) do |list, entry|
|
||||
next list unless @page_class.valid_page_name?(entry.name)
|
||||
sha = ref_map[ref]
|
||||
list << entry.page(self, @repo.commit(sha))
|
||||
list << entry.page(self, commit)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -519,6 +556,11 @@ module Gollum
|
||||
@repo.config['user.email'] || self.class.default_committer_email
|
||||
end
|
||||
|
||||
def commit_for(ref)
|
||||
@access.commit(ref)
|
||||
rescue Grit::GitRuby::Repository::NoSuchShaFound
|
||||
end
|
||||
|
||||
# Finds a full listing of files and their blob SHA for a given ref. Each
|
||||
# listing is cached based on its actual commit SHA.
|
||||
#
|
||||
@@ -526,62 +568,9 @@ module Gollum
|
||||
#
|
||||
# Returns an Array of BlobEntry instances.
|
||||
def tree_map_for(ref)
|
||||
sha = @ref_map[ref] || ref
|
||||
@tree_map[sha] || begin
|
||||
real_sha = @repo.git.rev_list({:max_count=>1}, ref)
|
||||
@ref_map[ref] = real_sha if real_sha != ref
|
||||
@tree_map[real_sha] ||= parse_tree_for(real_sha)
|
||||
end
|
||||
@access.tree(ref)
|
||||
rescue Grit::GitRuby::Repository::NoSuchShaFound
|
||||
[]
|
||||
end
|
||||
|
||||
# Finds the full listing of files and their blob SHA for a given commit
|
||||
# SHA. No caching or ref lookups are performed.
|
||||
#
|
||||
# sha - String commit SHA.
|
||||
#
|
||||
# Returns an Array of BlobEntry instances.
|
||||
def parse_tree_for(sha)
|
||||
tree = @repo.git.native(:ls_tree, {:r => true, :z => true}, sha)
|
||||
items = []
|
||||
tree.split("\0").each do |line|
|
||||
items << parse_tree_line(line)
|
||||
end
|
||||
items
|
||||
end
|
||||
|
||||
# Parses a line of output from the `ls-tree` command.
|
||||
#
|
||||
# line - A String line of output:
|
||||
# "100644 blob 839c2291b30495b9a882c17d08254d3c90d8fb53 Home.md"
|
||||
#
|
||||
# Returns an Array of BlobEntry instances.
|
||||
def parse_tree_line(line)
|
||||
data, name = line.split("\t")
|
||||
mode, type, sha = data.split(' ')
|
||||
name = decode_git_path(name)
|
||||
BlobEntry.new sha, name
|
||||
end
|
||||
|
||||
# Decode octal sequences (\NNN) in tree path names.
|
||||
#
|
||||
# path - String path name.
|
||||
#
|
||||
# Returns a decoded String.
|
||||
def decode_git_path(path)
|
||||
if path[0] == ?" && path[-1] == ?"
|
||||
path = path[1...-1]
|
||||
path.gsub!(/\\\d{3}/) { |m| m[1..-1].to_i(8).chr }
|
||||
end
|
||||
path.gsub!(/\\[rn"\\]/) { |m| eval(%("#{m.to_s}")) }
|
||||
path
|
||||
end
|
||||
|
||||
# Resets the ref and tree caches for this wiki.
|
||||
def clear_cache
|
||||
@ref_map = {}
|
||||
@tree_map = {}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
require File.join(File.dirname(__FILE__), *%w[helper])
|
||||
|
||||
context "GitAccess" do
|
||||
setup do
|
||||
@access = Gollum::GitAccess.new(testpath("examples/lotr.git"))
|
||||
end
|
||||
|
||||
test "#commit fills commit_map cache" do
|
||||
assert @access.commit_map.empty?
|
||||
actual = @access.repo.commits.first
|
||||
expected = @access.commit(actual.id)
|
||||
assert_equal actual.message, expected.message
|
||||
assert_equal actual.message, @access.commit_map[actual.id].message
|
||||
end
|
||||
|
||||
test "#commits uses commit_map" do
|
||||
actual = @access.repo.commits.first
|
||||
@access.commit_map['abc'] = 1
|
||||
commits = @access.commits('abc', actual.id)
|
||||
assert_equal 1, commits[0]
|
||||
assert_equal actual.message, commits[1].message
|
||||
end
|
||||
|
||||
test "#tree_map_for caches ref and tree" do
|
||||
assert @access.ref_map.empty?
|
||||
assert @access.tree_map.empty?
|
||||
@access.tree 'master'
|
||||
assert_equal({"master"=>"60f12f4254f58801b9ee7db7bca5fa8aeefaa56b"}, @access.ref_map)
|
||||
|
||||
map = @access.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 @access.tree_map.empty?
|
||||
@access.tree '60f12f4254f58801b9ee7db7bca5fa8aeefaa56b'
|
||||
assert @access.ref_map.empty?
|
||||
|
||||
entry = @access.tree_map['60f12f4254f58801b9ee7db7bca5fa8aeefaa56b'][0]
|
||||
assert_equal 'Bilbo-Baggins.md', entry.path
|
||||
end
|
||||
|
||||
test "cannot access commit from invalid ref" do
|
||||
assert_nil @access.commit('foo')
|
||||
end
|
||||
|
||||
test "cannot access sha from invalid ref" do
|
||||
assert_nil @access.ref_to_sha('foo')
|
||||
end
|
||||
|
||||
test "cannot access tree from invalid ref" do
|
||||
assert_equal [], @access.tree('foo')
|
||||
end
|
||||
end
|
||||
@@ -25,6 +25,31 @@ context "Markup" do
|
||||
end
|
||||
end
|
||||
|
||||
test "Gollum::Markup#render yields a DocumentFragment" do
|
||||
yielded = false
|
||||
@wiki.write_page("Yielded", :markdown, "abc", commit_details)
|
||||
|
||||
page = @wiki.page("Yielded")
|
||||
markup = Gollum::Markup.new(page)
|
||||
markup.render do |doc|
|
||||
assert_kind_of Nokogiri::HTML::DocumentFragment, doc
|
||||
yielded = true
|
||||
end
|
||||
assert yielded
|
||||
end
|
||||
|
||||
test "Gollum::Page#formatted_data yields a DocumentFragment" do
|
||||
yielded = false
|
||||
@wiki.write_page("Yielded", :markdown, "abc", commit_details)
|
||||
|
||||
page = @wiki.page("Yielded")
|
||||
page.formatted_data do |doc|
|
||||
assert_kind_of Nokogiri::HTML::DocumentFragment, doc
|
||||
yielded = true
|
||||
end
|
||||
assert yielded
|
||||
end
|
||||
|
||||
#########################################################################
|
||||
#
|
||||
# Links
|
||||
|
||||
+23
-23
@@ -60,29 +60,29 @@ 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 "#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"))
|
||||
|
||||
Reference in New Issue
Block a user