diff --git a/HISTORY.md b/HISTORY.md index e2620f58..e4f977dc 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,10 +1,14 @@ # HEAD +* Major Enhancements + * Add Page sidebars, similar to Page footers. * Minor Enhancements * 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 + rendering for added customization. * Bug Fixes * Use `@wiki.page_class` in Gollum::Markup where appropriate (#63). diff --git a/gollum.gemspec b/gollum.gemspec index e2586d7e..00666d58 100644 --- a/gollum.gemspec +++ b/gollum.gemspec @@ -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 diff --git a/lib/gollum.rb b/lib/gollum.rb index 78b0010a..6970d0be 100644 --- a/lib/gollum.rb +++ b/lib/gollum.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' diff --git a/lib/gollum/blob_entry.rb b/lib/gollum/blob_entry.rb index b224fc4a..cbadc01c 100644 --- a/lib/gollum/blob_entry.rb +++ b/lib/gollum/blob_entry.rb @@ -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. diff --git a/lib/gollum/file.rb b/lib/gollum/file.rb index 8e7c33d3..acea37a6 100644 --- a/lib/gollum/file.rb +++ b/lib/gollum/file.rb @@ -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 diff --git a/lib/gollum/frontend/views/page.rb b/lib/gollum/frontend/views/page.rb index 04f1e64a..03d20224 100644 --- a/lib/gollum/frontend/views/page.rb +++ b/lib/gollum/frontend/views/page.rb @@ -20,18 +20,29 @@ module Precious end def has_footer - @footer ||= @page.footer - !@footer.nil? + @footer = (@page.footer || false) if @footer.nil? + !!@footer end def footer_content - @footer ||= @page.footer - @footer.formatted_data + has_footer && @footer.formatted_data end def footer_format - @footer ||= @page.footer - @footer.format.to_s + has_footer && @footer.format.to_s + end + + def has_sidebar + @sidebar = (@page.sidebar || false) if @sidebar.nil? + !!@sidebar + end + + def sidebar_content + has_sidebar && @sidebar.formatted_data + end + + def sidebar_format + has_sidebar && @sidebar.format.to_s end end end diff --git a/lib/gollum/git_access.rb b/lib/gollum/git_access.rb new file mode 100644 index 00000000..9306c893 --- /dev/null +++ b/lib/gollum/git_access.rb @@ -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" => [, ]} + # + attr_reader :tree_map + + # Gets a Hash cache of commit SHAs to the Grit::Commit instance. + # + # {"abcd123" => } + # + 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 \ No newline at end of file diff --git a/lib/gollum/markup.rb b/lib/gollum/markup.rb index 4c72c3b9..e63e96b1 100644 --- a/lib/gollum/markup.rb +++ b/lib/gollum/markup.rb @@ -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>/, '') 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 diff --git a/lib/gollum/page.rb b/lib/gollum/page.rb index 6e2e66d7..5b888964 100644 --- a/lib/gollum/page.rb +++ b/lib/gollum/page.rb @@ -55,7 +55,7 @@ module Gollum # Returns a newly initialized Gollum::Page. def initialize(wiki) @wiki = wiki - @blob = nil + @blob = @footer = @sidebar = nil end # Public: The on-disk filename of the page including extension. @@ -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,14 @@ module Gollum # # Returns the footer Page or nil if none exists. def footer - return nil if page_match('_Footer', self.filename) + @footer ||= find_sub_page(:footer) + end - 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', '') + # Public: The sidebar Page. + # + # Returns the sidebar Page or nil if none exists. + def sidebar + @sidebar ||= find_sub_page(:sidebar) end # Gets a Boolean determining whether this page is a historical version. @@ -283,11 +278,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 +297,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 +351,29 @@ 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) + return nil if self.filename =~ /^_/ + 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 diff --git a/lib/gollum/sanitization.rb b/lib/gollum/sanitization.rb index 72ba2ec9..153cd570 100644 --- a/lib/gollum/sanitization.rb +++ b/lib/gollum/sanitization.rb @@ -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 diff --git a/lib/gollum/wiki.rb b/lib/gollum/wiki.rb index 6afd74da..9d9b7b10 100644 --- a/lib/gollum/wiki.rb +++ b/lib/gollum/wiki.rb @@ -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 diff --git a/test/examples/lotr.git/COMMIT_EDITMSG b/test/examples/lotr.git/COMMIT_EDITMSG new file mode 100644 index 00000000..25541c25 --- /dev/null +++ b/test/examples/lotr.git/COMMIT_EDITMSG @@ -0,0 +1 @@ +add sidebars diff --git a/test/examples/lotr.git/config b/test/examples/lotr.git/config index c53d818d..ec3337a4 100644 --- a/test/examples/lotr.git/config +++ b/test/examples/lotr.git/config @@ -1,5 +1,12 @@ [core] repositoryformatversion = 0 filemode = true - bare = true + bare = false + logallrefupdates = true ignorecase = true +[remote "origin"] + fetch = +refs/heads/*:refs/remotes/origin/* + url = /Users/rick/p/gollum/test/examples/lotr.git +[branch "master"] + remote = origin + merge = refs/heads/master diff --git a/test/examples/lotr.git/hooks/commit-msg.sample b/test/examples/lotr.git/hooks/commit-msg.sample index 6ef1d29d..b58d1184 100755 --- a/test/examples/lotr.git/hooks/commit-msg.sample +++ b/test/examples/lotr.git/hooks/commit-msg.sample @@ -1,7 +1,7 @@ #!/bin/sh # # An example hook script to check the commit log message. -# Called by git-commit with one argument, the name of the file +# Called by "git commit" with one argument, the name of the file # that has the commit message. The hook should exit with non-zero # status after issuing an appropriate message if it wants to stop the # commit. The hook is allowed to edit the commit message file. diff --git a/test/examples/lotr.git/hooks/post-update.sample b/test/examples/lotr.git/hooks/post-update.sample index 5323b56b..ec17ec19 100755 --- a/test/examples/lotr.git/hooks/post-update.sample +++ b/test/examples/lotr.git/hooks/post-update.sample @@ -5,4 +5,4 @@ # # To enable this hook, rename this file to "post-update". -exec git-update-server-info +exec git update-server-info diff --git a/test/examples/lotr.git/hooks/pre-commit.sample b/test/examples/lotr.git/hooks/pre-commit.sample index 439eefda..b187c4bb 100755 --- a/test/examples/lotr.git/hooks/pre-commit.sample +++ b/test/examples/lotr.git/hooks/pre-commit.sample @@ -1,13 +1,13 @@ #!/bin/sh # # An example hook script to verify what is about to be committed. -# Called by git-commit with no arguments. The hook should +# Called by "git commit" with no arguments. The hook should # exit with non-zero status after issuing an appropriate message if # it wants to stop the commit. # # To enable this hook, rename this file to "pre-commit". -if git-rev-parse --verify HEAD >/dev/null 2>&1 +if git rev-parse --verify HEAD >/dev/null 2>&1 then against=HEAD else diff --git a/test/examples/lotr.git/hooks/pre-rebase.sample b/test/examples/lotr.git/hooks/pre-rebase.sample index be1b06e2..9773ed4c 100755 --- a/test/examples/lotr.git/hooks/pre-rebase.sample +++ b/test/examples/lotr.git/hooks/pre-rebase.sample @@ -2,7 +2,7 @@ # # Copyright (c) 2006, 2008 Junio C Hamano # -# The "pre-rebase" hook is run just before "git-rebase" starts doing +# The "pre-rebase" hook is run just before "git rebase" starts doing # its job, and can prevent the command from running by exiting with # non-zero status. # @@ -43,7 +43,7 @@ git show-ref -q "$topic" || { } # Is topic fully merged to master? -not_in_master=`git-rev-list --pretty=oneline ^master "$topic"` +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` if test -z "$not_in_master" then echo >&2 "$topic is fully merged to master; better remove it." @@ -51,11 +51,11 @@ then fi # Is topic ever merged to next? If so you should not be rebasing it. -only_next_1=`git-rev-list ^master "^$topic" ${publish} | sort` -only_next_2=`git-rev-list ^master ${publish} | sort` +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` if test "$only_next_1" = "$only_next_2" then - not_in_topic=`git-rev-list "^$topic" master` + not_in_topic=`git rev-list "^$topic" master` if test -z "$not_in_topic" then echo >&2 "$topic is already up-to-date with master" @@ -64,8 +64,8 @@ then exit 0 fi else - not_in_next=`git-rev-list --pretty=oneline ^${publish} "$topic"` - perl -e ' + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' my $topic = $ARGV[0]; my $msg = "* $topic has commits already merged to public branch:\n"; my (%not_in_next) = map { @@ -157,13 +157,13 @@ B to be deleted. To compute (1): - git-rev-list ^master ^topic next - git-rev-list ^master next + git rev-list ^master ^topic next + git rev-list ^master next if these match, topic has not merged in next at all. To compute (2): - git-rev-list master..topic + git rev-list master..topic if this is empty, it is fully merged to "master". diff --git a/test/examples/lotr.git/hooks/prepare-commit-msg.sample b/test/examples/lotr.git/hooks/prepare-commit-msg.sample index 36524249..f093a02e 100755 --- a/test/examples/lotr.git/hooks/prepare-commit-msg.sample +++ b/test/examples/lotr.git/hooks/prepare-commit-msg.sample @@ -1,7 +1,7 @@ #!/bin/sh # # An example hook script to prepare the commit log message. -# Called by git-commit with the name of the file that has the +# Called by "git commit" with the name of the file that has the # commit message, followed by the description of the commit # message's source. The hook's purpose is to edit the commit # message file. If the hook fails with a non-zero status, @@ -22,10 +22,10 @@ case "$2,$3" in merge,) - perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; # ,|template,) -# perl -i.bak -pe ' +# /usr/bin/perl -i.bak -pe ' # print "\n" . `git diff --cached --name-status -r` # if /^#/ && $first++ == 0' "$1" ;; diff --git a/test/examples/lotr.git/hooks/update.sample b/test/examples/lotr.git/hooks/update.sample index fd63b2d6..71ab04ed 100755 --- a/test/examples/lotr.git/hooks/update.sample +++ b/test/examples/lotr.git/hooks/update.sample @@ -1,7 +1,7 @@ #!/bin/sh # # An example hook script to blocks unannotated tags from entering. -# Called by git-receive-pack with arguments: refname sha1-old sha1-new +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new # # To enable this hook, rename this file to "update". # @@ -64,7 +64,7 @@ zero="0000000000000000000000000000000000000000" if [ "$newrev" = "$zero" ]; then newrev_type=delete else - newrev_type=$(git-cat-file -t $newrev) + newrev_type=$(git cat-file -t $newrev) fi case "$refname","$newrev_type" in diff --git a/test/examples/lotr.git/index b/test/examples/lotr.git/index new file mode 100644 index 00000000..cc6fa46e Binary files /dev/null and b/test/examples/lotr.git/index differ diff --git a/test/examples/lotr.git/info/exclude b/test/examples/lotr.git/info/exclude index 2c87b72d..a5196d1b 100644 --- a/test/examples/lotr.git/info/exclude +++ b/test/examples/lotr.git/info/exclude @@ -1,4 +1,4 @@ -# git-ls-files --others --exclude-from=.git/info/exclude +# 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): diff --git a/test/examples/lotr.git/info/refs b/test/examples/lotr.git/info/refs deleted file mode 100644 index 23535fff..00000000 --- a/test/examples/lotr.git/info/refs +++ /dev/null @@ -1 +0,0 @@ -d61c3de65957b5997c236393b3ad4d70b5cd8931 refs/heads/master diff --git a/test/examples/lotr.git/logs/HEAD b/test/examples/lotr.git/logs/HEAD new file mode 100644 index 00000000..99c12840 --- /dev/null +++ b/test/examples/lotr.git/logs/HEAD @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 60f12f4254f58801b9ee7db7bca5fa8aeefaa56b rick 1291341857 -0800 clone: from /Users/rick/p/gollum/test/examples/lotr.git +60f12f4254f58801b9ee7db7bca5fa8aeefaa56b a8ad3c09dd842a3517085bfadd37718856dee813 rick 1291341922 -0800 commit: add sidebars diff --git a/test/examples/lotr.git/logs/refs/heads/master b/test/examples/lotr.git/logs/refs/heads/master new file mode 100644 index 00000000..99c12840 --- /dev/null +++ b/test/examples/lotr.git/logs/refs/heads/master @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 60f12f4254f58801b9ee7db7bca5fa8aeefaa56b rick 1291341857 -0800 clone: from /Users/rick/p/gollum/test/examples/lotr.git +60f12f4254f58801b9ee7db7bca5fa8aeefaa56b a8ad3c09dd842a3517085bfadd37718856dee813 rick 1291341922 -0800 commit: add sidebars diff --git a/test/examples/lotr.git/objects/84/0ec5b1ba1320e8ec443f28f99566f615d5af10 b/test/examples/lotr.git/objects/84/0ec5b1ba1320e8ec443f28f99566f615d5af10 new file mode 100644 index 00000000..a1e90909 Binary files /dev/null and b/test/examples/lotr.git/objects/84/0ec5b1ba1320e8ec443f28f99566f615d5af10 differ diff --git a/test/examples/lotr.git/objects/a3/1ca2a7c352c92531a8b99815d15843b259e814 b/test/examples/lotr.git/objects/a3/1ca2a7c352c92531a8b99815d15843b259e814 new file mode 100644 index 00000000..3876f6c3 Binary files /dev/null and b/test/examples/lotr.git/objects/a3/1ca2a7c352c92531a8b99815d15843b259e814 differ diff --git a/test/examples/lotr.git/objects/a8/ad3c09dd842a3517085bfadd37718856dee813 b/test/examples/lotr.git/objects/a8/ad3c09dd842a3517085bfadd37718856dee813 new file mode 100644 index 00000000..efd0cc98 Binary files /dev/null and b/test/examples/lotr.git/objects/a8/ad3c09dd842a3517085bfadd37718856dee813 differ diff --git a/test/examples/lotr.git/packed-refs b/test/examples/lotr.git/packed-refs index 0a68312a..093dfa7f 100644 --- a/test/examples/lotr.git/packed-refs +++ b/test/examples/lotr.git/packed-refs @@ -1,2 +1,2 @@ # pack-refs with: peeled -d61c3de65957b5997c236393b3ad4d70b5cd8931 refs/heads/master +60f12f4254f58801b9ee7db7bca5fa8aeefaa56b refs/remotes/origin/master diff --git a/test/examples/lotr.git/refs/heads/master b/test/examples/lotr.git/refs/heads/master index 3f114d47..c64ca983 100644 --- a/test/examples/lotr.git/refs/heads/master +++ b/test/examples/lotr.git/refs/heads/master @@ -1 +1 @@ -60f12f4254f58801b9ee7db7bca5fa8aeefaa56b \ No newline at end of file +a8ad3c09dd842a3517085bfadd37718856dee813 diff --git a/test/examples/lotr.git/refs/remotes/origin/HEAD b/test/examples/lotr.git/refs/remotes/origin/HEAD new file mode 100644 index 00000000..6efe28ff --- /dev/null +++ b/test/examples/lotr.git/refs/remotes/origin/HEAD @@ -0,0 +1 @@ +ref: refs/remotes/origin/master diff --git a/test/examples/lotr/Bilbo-Baggins.md b/test/examples/lotr/Bilbo-Baggins.md new file mode 100644 index 00000000..2cb9156a --- /dev/null +++ b/test/examples/lotr/Bilbo-Baggins.md @@ -0,0 +1,13 @@ +# Bilbo Baggins + +Bilbo Baggins is the protagonist of The [[Hobbit]] and also makes a few +appearances in The Lord of the Rings, two of the most well-known of [[J. R. R. +Tolkien]]'s fantasy writings. The story of The Hobbit featuring Bilbo is also +retold from a different perspective in the Chapter The Quest of Erebor in +Unfinished Tales. + +In Tolkien's narrative conceit, in which all the writings of Middle-earth are +'really' translations from the fictitious volume of The Red Book of Westmarch, +Bilbo is the author of The Hobbit and translator of The Silmarillion. + +From [http://en.wikipedia.org/wiki/Bilbo_Baggins](http://en.wikipedia.org/wiki/Bilbo_Baggins). diff --git a/test/examples/lotr/Data.csv b/test/examples/lotr/Data.csv new file mode 100644 index 00000000..c3b43e9f --- /dev/null +++ b/test/examples/lotr/Data.csv @@ -0,0 +1,3 @@ +FirstName,LastName +Bilbo,Baggins +Frodo,Baggins diff --git a/test/examples/lotr/Home.textile b/test/examples/lotr/Home.textile new file mode 100644 index 00000000..fae7ef53 --- /dev/null +++ b/test/examples/lotr/Home.textile @@ -0,0 +1,3 @@ +h1. The LOTR Wiki + +This wiki is awesome. You can learn about [[Bilbo Baggins]] or some [[evil|Eye Of Sauron]] stuff. diff --git a/test/examples/lotr/Mordor/Eye-Of-Sauron.md b/test/examples/lotr/Mordor/Eye-Of-Sauron.md new file mode 100644 index 00000000..936b83ee --- /dev/null +++ b/test/examples/lotr/Mordor/Eye-Of-Sauron.md @@ -0,0 +1,37 @@ +# Eye **Of** Sauron + +Here are some pictures of the Eye of Sauron! + +Just the photo. + +[[/Mordor/eye.jpg]] + +With alt. + +[[/Mordor/eye.jpg|alt=Eye of Sauron]] + +With frame and caption. + +[[/Mordor/eye.jpg|frame|alt=Eye of Sauron]] + +Align left. + +[[/Mordor/eye.jpg|align=left]] + +Alight center. + +[[/Mordor/eye.jpg|align=center]] + +Alight right. + +[[/Mordor/eye.jpg|align=right]] + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas interdum velit eu justo rutrum vitae semper urna porttitor. Sed viverra bibendum tincidunt. Curabitur vel mi sed nisl vestibulum lobortis eu ac nisl. Morbi fringilla adipiscing felis. Mauris luctus interdum accumsan. Integer leo mauris, dapibus a sollicitudin non, varius non erat. Donec eu dictum orci. Morbi viverra eleifend felis, et adipiscing neque consequat a. Vestibulum accumsan ligula suscipit mi rhoncus ac gravida lectus tincidunt. Donec interdum, [[/Mordor/eye.jpg|float|frame|alt=FIRE FIRE FIRE]] lorem sed interdum molestie, est ipsum pharetra est, sit amet eleifend purus eros at ligula. Aliquam erat volutpat. Sed dignissim interdum ipsum, et pulvinar lectus faucibus et. Ut at lacus risus, non lobortis erat. Proin malesuada sagittis mauris, in posuere turpis tincidunt eu. Nunc accumsan, ligula ut rutrum aliquet, neque metus suscipit ligula, in aliquam augue velit vel orci. Aliquam diam lectus, posuere id faucibus sed, aliquam vel erat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas interdum velit eu justo rutrum vitae semper urna porttitor. Sed viverra bibendum tincidunt. Curabitur vel mi sed nisl vestibulum lobortis eu ac nisl. Morbi fringilla adipiscing felis. Mauris luctus interdum accumsan. Integer leo mauris, dapibus a sollicitudin non, varius non erat. Donec eu dictum orci. [[/Mordor/eye.jpg|float|align=right]] Morbi viverra eleifend felis, et adipiscing neque consequat a. Vestibulum accumsan ligula suscipit mi rhoncus ac gravida lectus tincidunt. Donec interdum, lorem sed interdum molestie, est ipsum pharetra est, sit amet eleifend purus eros at ligula. Aliquam erat volutpat. Sed dignissim interdum ipsum, et pulvinar lectus faucibus et. Ut at lacus risus, non lobortis erat. Proin malesuada sagittis mauris, in posuere turpis tincidunt eu. Nunc accumsan, ligula ut rutrum aliquet, neque metus suscipit ligula, in aliquam augue velit vel orci. Aliquam diam lectus, posuere id faucibus sed, aliquam vel erat. + +Smaller width. + +[[/Mordor/eye.jpg|width=100px]] + +Smaller height. + +[[/Mordor/eye.jpg|height=100px]] diff --git a/test/examples/lotr/Mordor/_Footer.md b/test/examples/lotr/Mordor/_Footer.md new file mode 100644 index 00000000..9697dc65 --- /dev/null +++ b/test/examples/lotr/Mordor/_Footer.md @@ -0,0 +1 @@ +Ones does not simply **walk** into Mordor! diff --git a/test/examples/lotr/Mordor/_Sidebar.md b/test/examples/lotr/Mordor/_Sidebar.md new file mode 100644 index 00000000..9697dc65 --- /dev/null +++ b/test/examples/lotr/Mordor/_Sidebar.md @@ -0,0 +1 @@ +Ones does not simply **walk** into Mordor! diff --git a/test/examples/lotr/Mordor/eye.jpg b/test/examples/lotr/Mordor/eye.jpg new file mode 100644 index 00000000..714323c1 Binary files /dev/null and b/test/examples/lotr/Mordor/eye.jpg differ diff --git a/test/examples/lotr/Mordor/todo.txt b/test/examples/lotr/Mordor/todo.txt new file mode 100644 index 00000000..0ade1e29 --- /dev/null +++ b/test/examples/lotr/Mordor/todo.txt @@ -0,0 +1 @@ +[ ] Write section on Ents diff --git a/test/examples/lotr/My-Precious.md b/test/examples/lotr/My-Precious.md new file mode 100644 index 00000000..aab61fe8 --- /dev/null +++ b/test/examples/lotr/My-Precious.md @@ -0,0 +1 @@ +One ring to rule them all! diff --git a/test/examples/lotr/_Footer.md b/test/examples/lotr/_Footer.md new file mode 100644 index 00000000..ecda3205 --- /dev/null +++ b/test/examples/lotr/_Footer.md @@ -0,0 +1 @@ +Lord of the Rings wiki \ No newline at end of file diff --git a/test/examples/lotr/_Sidebar.md b/test/examples/lotr/_Sidebar.md new file mode 100644 index 00000000..ecda3205 --- /dev/null +++ b/test/examples/lotr/_Sidebar.md @@ -0,0 +1 @@ +Lord of the Rings wiki \ No newline at end of file diff --git a/test/static/default/Bilbo-Baggins.html b/test/static/default/Bilbo-Baggins.html new file mode 100644 index 00000000..9dd2c777 --- /dev/null +++ b/test/static/default/Bilbo-Baggins.html @@ -0,0 +1,41 @@ + + + + + + + Bilbo Baggins + + + +

+
+
+
+
+

Bilbo Baggins

+ +

Bilbo Baggins is the protagonist of The Hobbit and also makes a few +appearances in The Lord of the Rings, two of the most well-known of J. R. R. +Tolkien's fantasy writings. The story of The Hobbit featuring Bilbo is also +retold from a different perspective in the Chapter The Quest of Erebor in +Unfinished Tales.

+ +

In Tolkien's narrative conceit, in which all the writings of Middle-earth are +'really' translations from the fictitious volume of The Red Book of Westmarch, +Bilbo is the author of The Hobbit and translator of The Silmarillion.

+ +

From http://en.wikipedia.org/wiki/Bilbo_Baggins.

+
+
+
+ +
+ +
+ + + + diff --git a/test/static/default/Eye-Of-Sauron.html b/test/static/default/Eye-Of-Sauron.html new file mode 100644 index 00000000..6619be30 --- /dev/null +++ b/test/static/default/Eye-Of-Sauron.html @@ -0,0 +1,65 @@ + + + + + + + Eye Of Sauron + + + +
+
+
+
+
+

Eye Of Sauron

+ +

Here are some pictures of the Eye of Sauron!

+ +

Just the photo.

+ +

+ +

With alt.

+ +

Eye of Sauron

+ +

With frame and caption.

+ +

Eye of SauronEye of Sauron

+ +

Align left.

+ +

+ +

Alight center.

+ +

+ +

Alight right.

+ +

+ +

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas interdum velit eu justo rutrum vitae semper urna porttitor. Sed viverra bibendum tincidunt. Curabitur vel mi sed nisl vestibulum lobortis eu ac nisl. Morbi fringilla adipiscing felis. Mauris luctus interdum accumsan. Integer leo mauris, dapibus a sollicitudin non, varius non erat. Donec eu dictum orci. Morbi viverra eleifend felis, et adipiscing neque consequat a. Vestibulum accumsan ligula suscipit mi rhoncus ac gravida lectus tincidunt. Donec interdum, FIRE FIRE FIREFIRE FIRE FIRE lorem sed interdum molestie, est ipsum pharetra est, sit amet eleifend purus eros at ligula. Aliquam erat volutpat. Sed dignissim interdum ipsum, et pulvinar lectus faucibus et. Ut at lacus risus, non lobortis erat. Proin malesuada sagittis mauris, in posuere turpis tincidunt eu. Nunc accumsan, ligula ut rutrum aliquet, neque metus suscipit ligula, in aliquam augue velit vel orci. Aliquam diam lectus, posuere id faucibus sed, aliquam vel erat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas interdum velit eu justo rutrum vitae semper urna porttitor. Sed viverra bibendum tincidunt. Curabitur vel mi sed nisl vestibulum lobortis eu ac nisl. Morbi fringilla adipiscing felis. Mauris luctus interdum accumsan. Integer leo mauris, dapibus a sollicitudin non, varius non erat. Donec eu dictum orci. Morbi viverra eleifend felis, et adipiscing neque consequat a. Vestibulum accumsan ligula suscipit mi rhoncus ac gravida lectus tincidunt. Donec interdum, lorem sed interdum molestie, est ipsum pharetra est, sit amet eleifend purus eros at ligula. Aliquam erat volutpat. Sed dignissim interdum ipsum, et pulvinar lectus faucibus et. Ut at lacus risus, non lobortis erat. Proin malesuada sagittis mauris, in posuere turpis tincidunt eu. Nunc accumsan, ligula ut rutrum aliquet, neque metus suscipit ligula, in aliquam augue velit vel orci. Aliquam diam lectus, posuere id faucibus sed, aliquam vel erat.

+ +

Smaller width.

+ +

+ +

Smaller height.

+ +

+
+
+
+ +
+ +
+ + + + diff --git a/test/static/default/My-Precious.html b/test/static/default/My-Precious.html new file mode 100644 index 00000000..588bc404 --- /dev/null +++ b/test/static/default/My-Precious.html @@ -0,0 +1,29 @@ + + + + + + + My Precious + + + +
+
+
+
+
+

One ring to rule them all!

+
+
+
+ +
+ +
+ + + + diff --git a/test/static/default/css/gollum.css b/test/static/default/css/gollum.css new file mode 100644 index 00000000..627d98ef --- /dev/null +++ b/test/static/default/css/gollum.css @@ -0,0 +1,408 @@ +/* + gollum.css + A basic stylesheet for Gollum +*/ + +/* @section core */ +body, html { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 10px; /* -> 1em */ + margin: 0; + padding: 0; +} + +#wiki-wrapper { + margin: 0 auto; + overflow: visible; + width: 80%; +} + +a:link { + color: #4183c4; + text-decoration: none; +} + +a:hover, a:visited { + text-decoration: underline; +} + + +/* @section head */ +#head { + border-bottom: 1px solid #ccc; + margin: 4.5em 0 0.5em; + padding: 0.5em 0; + overflow: hidden; +} + + #head h1 { + font-size: 3.3em; + float: left; + line-height: normal; + margin: 0; + padding: 0.08em 0 0 0; + } + + #head ul.actions { + float: right; + } + + +/* @section content */ +#wiki-content { + height: 1%; + overflow: visible; +} + + #wiki-content .wrap { + height: 1%; + overflow: auto; + } + + /* @section comments */ + #wiki-body #inline-comment { + display: none; /* todo */ + } + + /* @section body */ + #wiki-body { + float: left; + margin-right: 3%; + width: 70%; + } + + /* @section rightbar */ + #wiki-rightbar { + float: right; + width: 27%; + } + + #wiki-rightbar #nav { + background-color: #f7f7f7; + border: 1px solid #ddd; + margin-top: 1.5em; + padding: 1em; + + border-radius: 0.5em; + -moz-border-radius: 0.5em; + -webkit-border-radius: 0.5em; + } + + #wiki-rightbar #nav { + font-size: 1.2em; + line-height: 1.5em; + } + + #wiki-rightbar #nav p.parent { + border-bottom: 1px solid #bbb; + font-weight: bold; + margin: 0 0 0.5em 0; + padding: 0 0 0.5em 0; + text-shadow: 0 1px 0 #fff; + } + + /* Back arrow */ + #wiki-rightbar #nav p.parent:before { + color: #666; + content: "← "; + } + + #wiki-rightbar #nav h3 { + font-size: 1.2em; + color: #333; + margin: 1.2em 0 0; + padding: 0; + text-shadow: 0 1px 0 #fff; + } + + #wiki-rightbar #nav ul { + margin: 0.5em 0 1em; + padding: 0; + } + + #wiki-rightbar #nav ul li { + color: #bbb; + list-style-position: outside; + list-style-type: none; + margin: 0 0 0 1em; + padding: 0; + line-height: 1.75em; + } + + #wiki-rightbar #nav ul li:hover { + list-style-type: square; + } + + #wiki-rightbar #nav ul li a { + font-weight: bold; + text-shadow: 0 1px 0 #fff; + } + + /* @section footer */ + #wiki-footer { + clear: both; + margin: 2em 0 5em; + } + + .has-rightbar #wiki-footer { + width: 70%; + } + + #wiki-footer #footer-content { + background-color: #f7f7f7; + border: 1px solid #ddd; + font-size: 1.2em; + line-height: 1.5em; + margin-top: 1.5em; + padding: 1em; + + border-radius: 0.5em; + -moz-border-radius: 0.5em; + -webkit-border-radius: 0.5em; + } + + #wiki-footer #footer-content h3 { + font-size: 1.2em; + color: #333; + margin: 0; + padding: 0 0 0.2em; + text-shadow: 0 1px 0 #fff; + } + + #wiki-footer #footer-content p { + margin: 0.5em 0 0; + padding: 0; + } + + #wiki-footer #footer-content ul.links { + margin: 0.5em 0 0; + overflow: hidden; + padding: 0; + } + + #wiki-footer #footer-content ul.links li { + color: #999; + float: left; + list-style-position: inside; + list-style-type: square; + padding: 0; + margin-left: 0.75em; + } + + #wiki-footer #footer-content ul.links li a { + font-weight: bold; + text-shadow: 0 1px 0 #fff; + } + + #wiki-footer #footer-content ul.links li:first-child { + list-style-type: none; + margin: 0; + } + + .ff #wiki-footer #footer-content ul.links li:first-child { + margin: 0 -0.75em 0 0; + } + + /* @section page-footer */ + .page #footer { + border-top: 1px solid #ccc; + margin: 1em 0 7em; + } + + #footer p#last-edit { + font-size: 1.2em; + line-height: 1.6em; + color: #999; + margin: 0.9em 0; + } + + #footer p#last-edit span.username { + font-weight: bold; + } + + +/* @section history */ +.history h1 { + color: #999; + font-weight: normal; +} + + .history h1 strong { + color: #000; + font-weight: bold; + } + +#wiki-history { + margin-top: 3em; +} + + #wiki-history fieldset { + border: 0; + margin: 2em 0; + padding: 0; + } + + #wiki-history table, #wiki-history tbody { + border-collapse: collapse; + padding: 0; + margin: 0; + width: 100%; + } + + #wiki-history table tr { + padding: 0; + margin: 0; + } + + #wiki-history table tr { + background-color: #ebf2f6; + } + + #wiki-history table tr td { + border: 1px solid #c0dce9; + font-size: 1.2em; + line-height: 1.6em; + margin: 0; + padding: 0.3em 0.7em; + } + + #wiki-history table tr td.checkbox { + padding: 0.3em; + } + + #wiki-history table tr td.checkbox input { + cursor: pointer; + display: block; + padding-right: 0; + padding-top: 0.4em; + margin-right: -0.2em; + } + + #wiki-history table tr:nth-child(2n), + #wiki-history table tr.alt-row { + background-color: #f3f7fa; + } + + #wiki-history table tr.selected { + background-color: #ffffea !important; + z-index: 100; + } + + #wiki-history table tr td.commit-name { + border-right: none; + } + + #wiki-history table tr td.commit-name span.time-elapsed { + color: #999; + } + + #wiki-history table tr td.author { + width: 20%; + } + + #wiki-history table tr td.author a { + color: #000; + font-weight: bold; + } + + #wiki-history table tr td.author a span.username { + display: block; + padding-top: 3px; + } + + #wiki-history table tr td img { + background-color: #fff; + border: 1px solid #999; + display: block; + float: left; + height: 18px; + overflow: hidden; + margin: 0 0.5em 0 0; + width: 18px; + padding: 2px; + } + + #wiki-history table tr td.commit-name a { + font-size: 0.9em; + font-family: 'Monaco', 'Andale Mono', Consolas, 'Courier New', monospace; + padding: 0 0.2em; + } + + #wiki-history table tr td.revert-action { + border-left: 0; + text-align: right; + } + + #wiki-history table tr td.revert-action a { + font-weight: bold; + } + + #wiki-history table tr td.revert-action a span { + font-size: 0.9em; + font-family: 'Monaco', 'Andale Mono', Consolas, 'Courier New', monospace; + } + +.history #wiki-history ul.actions li, +.history #footer ul.actions li { + margin: 0 0.6em 0 0; +} + + +/* @section edit */ +.edit h1 { + color: #999; + font-weight: normal; +} + + .edit h1 strong { + color: #000; + font-weight: bold; + } + + + +/* @control minibutton */ +ul.actions { + display: block; + list-style-type: none; + overflow: hidden; + padding: 0; + } + + ul.actions li { + float: left; + font-size: 1.2em; + margin-left: 0.6em; + } + +.minibutton a { + background-color: #f7f7f7; + border: 1px solid #d4d4d4; + color: #333; + display: block; + font-weight: bold; + margin: 0; + padding: 0.4em 1em; + + text-shadow: 0 1px 0 #fff; + + filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f4f4f4', endColorstr='#ececec'); + background: -webkit-gradient(linear, left top, left bottom, from(#f4f4f4), to(#ececec)); + background: -moz-linear-gradient(top, #f4f4f4, #ececec); + + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} + +.minibutton a:hover { + background: #3072b3; + border-color: #518cc6 #518cc6 #2a65a0; + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3); + text-decoration: none; + + filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#599bdc', endColorstr='#3072b3'); + background: -webkit-gradient(linear, left top, left bottom, from(#599bdc), to(#3072b3)); + background: -moz-linear-gradient(top, #599bdc, #3072b3); +} \ No newline at end of file diff --git a/test/static/default/css/template.css b/test/static/default/css/template.css new file mode 100644 index 00000000..882877ff --- /dev/null +++ b/test/static/default/css/template.css @@ -0,0 +1,146 @@ +/* + template.css + Wiki content formatting + Keeping this file separate so it can be easily swapped out if you + want to format your wiki content differently from the default. +*/ + +#template { + margin-bottom: 4em; /* Give it some breathing room */ +} + +.has-footer #template { + margin: 0; +} + +#template p { + font-size: 1.4em; + line-height: 1.6em; +} + + /* See http://webtypography.net/Rhythm_and_Proportion/ */ + #template p + p { + margin: -0.75em 0 0; + text-indent: 1em; + } + + /* Everybody loves type ornaments */ + #template p:last-child:after { + color: #999; + content: " ❈"; + font-size: 0.8em; + } + + #template blockquote p:last-child:after { + content: none; + } + +#template a:link { + color: #4183c4; + text-decoration: none; +} + +#template a:hover, #template a:visited { + text-decoration: underline; +} + +#template ul, #template ol { + margin: 1.0em 0 0 2.0em; + list-style-position: outside; + padding: 0; + +} + +#template p + ul, #template p + ol, +#template ul li > ul, #template ol li > ol { + margin-top: 0; +} + +#template ul li > ul, #template ol li > ol { + margin-left: 0; +} + + #template ul { + list-style-type: square; + } + + #template ol li > ol li { + font-size: 1.0em !important; + list-style-type: lower-roman; + list-style-position: inside; + } + + #template ol li > ol li > ol li { + list-style-type: lower-alpha; + } + + #template ol li > ol li > ol li > ol li { + list-style-type: lower-greek; + } + +#template ul li, #template ol li { + font-size: 1.4em; + line-height: 1.6em; + padding-top: 0.1em; /* Line up ordinals */ +} + +#template blockquote { + margin: 0 4.0em 0 2.0em; + padding: 0; +} + + #template blockquote p { + color: #888; + font-style: italic; + } + + +/* Headings */ +#template h1, #template h2, #template h3, +#template h4, #template h5, #template h6 { + margin: 0; + padding: 0.5em 0 0; +} + +#template h1 { + font-size: 2.6em; + font-weight: bold; +} + +#template h2 { + font-size: 2.2em; + font-weight: bold; +} + +#template h3 { + font-size: 2.0em; + font-weight: bold; +} + +#template h4 { + font-size: 1.8em; + font-weight: bold; +} + +#template h5 { + font-size: 1.6em; + font-weight: bold; + +} + +#template h6 { + font-size: 1.4em; + font-weight: bold; + margin-top: 1.0em; + text-transform: uppercase; /* all caps */ +} + + +/* Code-related */ +#template p code { + background-color: #f7f7f7; + border: 1px solid #ddd; + color: #222; /* This is a little heavy when #000 */ + font-family: Consolas, Monaco, "Courier New", monospace; + padding: 0.15em 0.3em; +} \ No newline at end of file diff --git a/test/static/default/index.html b/test/static/default/index.html new file mode 100644 index 00000000..58d42871 --- /dev/null +++ b/test/static/default/index.html @@ -0,0 +1,30 @@ + + + + + + + The LOTR Wiki + + + +
+
+
+
+
+

The LOTR Wiki

+

This wiki is awesome. You can learn about Bilbo Baggins or some evil stuff.

+
+
+
+ +
+ +
+ + + + diff --git a/test/test_git_access.rb b/test/test_git_access.rb new file mode 100644 index 00000000..ceb24cc6 --- /dev/null +++ b/test/test_git_access.rb @@ -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"=>"a8ad3c09dd842a3517085bfadd37718856dee813"}, @access.ref_map) + + map = @access.tree_map['a8ad3c09dd842a3517085bfadd37718856dee813'] + 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 \ No newline at end of file diff --git a/test/test_markup.rb b/test/test_markup.rb index c75ad1a6..892685af 100644 --- a/test/test_markup.rb +++ b/test/test_markup.rb @@ -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 diff --git a/test/test_page.rb b/test/test_page.rb index 1316c713..ed2e7d5b 100644 --- a/test/test_page.rb +++ b/test/test_page.rb @@ -109,6 +109,25 @@ context "Page" do test "footer itself" do footer = @wiki.page("_Footer") assert_nil footer.footer + assert_nil footer.sidebar + end + + test "top level sidebar" do + sidebar = @wiki.page('Home').sidebar + assert_equal 'Lord of the Rings wiki', sidebar.raw_data + assert_equal '_Sidebar.md', sidebar.path + end + + test "nested sidebar" do + sidebar = @wiki.page('Eye Of Sauron').sidebar + assert_equal "Ones does not simply **walk** into Mordor!\n", sidebar.raw_data + assert_equal "Mordor/_Sidebar.md", sidebar.path + end + + test "sidebar itself" do + sidebar = @wiki.page("_Sidebar") + assert_nil sidebar.footer + assert_nil sidebar.sidebar end test "cannot convert non string to human readable page title" do diff --git a/test/test_wiki.rb b/test/test_wiki.rb index c4beadea..fde5580b 100644 --- a/test/test_wiki.rb +++ b/test/test_wiki.rb @@ -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"))