gollum-lib-4.2.7/0000755000004100000410000000000013172672532013627 5ustar www-datawww-datagollum-lib-4.2.7/gollum-lib_java.gemspec0000644000004100000410000000041613172672532020241 0ustar www-datawww-datarequire File.join(File.dirname(__FILE__), 'gemspec.rb') require File.join(File.dirname(__FILE__), 'lib', 'gollum-lib', 'version.rb') default_adapter = ['gollum-rjgit_adapter', '~> 0.3'] Gem::Specification.new &specification(Gollum::Lib::VERSION, default_adapter, "java")gollum-lib-4.2.7/Rakefile0000644000004100000410000001110513172672532015272 0ustar www-datawww-datarequire 'rubygems' require 'rake' require 'date' ############################################################################# # # Helper functions # ############################################################################# def name "gollum-lib" end def version line = File.read("lib/gollum-lib/version.rb")[/^\s*VERSION\s*=\s*.*/] line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1] end # assumes x.y.z all digit version def next_version # x.y.z v = version.split '.' # bump z v[-1] = v[-1].to_i + 1 v.join '.' end def bump_version old_file = File.read("lib/gollum-lib/version.rb") old_version_line = old_file[/^\s*VERSION\s*=\s*.*/] new_version = next_version # replace first match of old version with new version old_file.sub!(old_version_line, " VERSION = '#{new_version}'") File.write("lib/gollum-lib/version.rb", old_file) new_version end def date Date.today.to_s end def rubyforge_project name end def gemspec_file "gemspec.rb" end def gemspecs ["#{name}.gemspec", "#{name}_java.gemspec"] end def gem_files ["#{name}-#{version}.gem", "#{name}-#{version}-java.gem"] end def replace_header(head, header_name) head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"} end ############################################################################# # # Standard tasks # ############################################################################# task :default => :test require 'rake/testtask' Rake::TestTask.new(:test) do |test| test.libs << 'lib' << 'test' << '.' test.pattern = 'test/**/test_*.rb' test.verbose = true end desc "Generate RCov test coverage and open in your browser" task :coverage do require 'rcov' sh "rm -fr coverage" sh "rcov test/test_*.rb" sh "open coverage/index.html" end desc "Open an irb session preloaded with this library" task :console do sh "irb -rubygems -r ./lib/#{name}.rb" end ############################################################################# # # Custom tasks (add your own tasks here) # ############################################################################# desc "Update version number and gemspec" task :bump do puts "Updated version to #{bump_version}" # Execute does not invoke dependencies. # Manually invoke gemspec then validate. Rake::Task[:gemspec].execute Rake::Task[:validate].execute end desc "Build and install" task :install => :build do sh "gem install --local --no-ri --no-rdoc pkg/#{name}-#{version}.gem" end ############################################################################# # # Packaging tasks # ############################################################################# desc 'Create a release build' task :release => :build do unless `git branch` =~ /^\* master$/ puts "You must be on the master branch to release!" exit! end sh "git commit --allow-empty -a -m 'Release #{version}'" sh "git pull --rebase origin master" sh "git tag v#{version}" sh "git push origin master" sh "git push origin v#{version}" sh "gem push pkg/#{name}-#{version}.gem" sh "gem push pkg/#{name}-#{version}-java.gem" end desc 'Publish to rubygems. Same as release' task :publish => :release desc 'Build gem' task :build => :gemspec do sh "mkdir -p pkg" gemspecs.each do |gemspec| sh "gem build #{gemspec}" end gem_files.each do |gem_file| sh "mv #{gem_file} pkg" end end desc 'Update gemspec' task :gemspec => :validate do # read spec file and split out manifest section spec = File.read(gemspec_file) head, _manifest, tail = spec.split(" # = MANIFEST =\n") # replace name version and date replace_header(head, :name) replace_header(head, :date) #comment this out if your rubyforge_project has a different name replace_header(head, :rubyforge_project) # determine file list from git ls-files files = `git ls-files`. split("\n"). sort. reject { |file| file =~ /^\./ }. reject { |file| file =~ /^(rdoc|pkg|test|Home\.md|\.gitattributes|Guardfile)/ }. map { |file| " #{file}" }. join("\n") # piece file back together and write manifest = " s.files = %w(\n#{files}\n )\n" spec = [head, manifest, tail].join(" # = MANIFEST =\n") File.open(gemspec_file, 'w') { |io| io.write(spec) } puts "Updated #{gemspec_file}" end desc 'Validate lib files and version file' task :validate do libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"] unless libfiles.empty? puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir." exit! end unless Dir['VERSION*'].empty? puts "A `VERSION` file at root level violates Gem best practices." exit! end end gollum-lib-4.2.7/Gemfile0000644000004100000410000000007413172672532015123 0ustar www-datawww-datasource 'https://rubygems.org' gemspec :name => 'gollum-lib' gollum-lib-4.2.7/HISTORY.md0000644000004100000410000000105713172672532015315 0ustar www-datawww-data# v4.2.1 * Performances improvements * Dependency updates # v4.2.0 * Changes since v4.1.0: ** Various performance improvements ** Dependency updates ** Bugfixes ** New Macro for listing contents of (sub)directories: `Navigation()` ** Table of Contents now supports setting max heading level # v4.0.2 /2015-0119 * Bugfixes # v4.0.1 /2014-12-04 * Security fix for [remote code execution issue](https://github.com/gollum/gollum/issues/913). Please update! # v0.0.1 / 2013-03-19 * First release, extrated from https://github.com/gollum/gollum gollum-lib-4.2.7/gollum-lib.gemspec0000644000004100000410000000056113172672532017241 0ustar www-datawww-datarequire File.join(File.dirname(__FILE__), 'gemspec.rb') require File.join(File.dirname(__FILE__), 'lib', 'gollum-lib', 'version.rb') if RUBY_PLATFORM == 'java' then default_adapter = ['gollum-rjgit_adapter', '~> 0.3'] else default_adapter = ['gollum-grit_adapter', '~> 1.0'] end Gem::Specification.new &specification(Gollum::Lib::VERSION, default_adapter)gollum-lib-4.2.7/lib/0000755000004100000410000000000013172672532014375 5ustar www-datawww-datagollum-lib-4.2.7/lib/gollum-lib.rb0000644000004100000410000000376213172672532016775 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ # stdlib require 'digest/md5' require 'digest/sha1' require 'ostruct' require 'pathname' DEFAULT_ADAPTER = RUBY_PLATFORM == 'java' ? 'rjgit_adapter' : 'grit_adapter' if defined?(Gollum::GIT_ADAPTER) require "#{Gollum::GIT_ADAPTER.downcase}_adapter" else require DEFAULT_ADAPTER end # external require 'github/markup' require 'sanitize' require 'gemojione' # internal require File.expand_path('../gollum-lib/git_access', __FILE__) require File.expand_path('../gollum-lib/hook', __FILE__) require File.expand_path('../gollum-lib/committer', __FILE__) require File.expand_path('../gollum-lib/pagination', __FILE__) require File.expand_path('../gollum-lib/blob_entry', __FILE__) require File.expand_path('../gollum-lib/wiki', __FILE__) require File.expand_path('../gollum-lib/page', __FILE__) require File.expand_path('../gollum-lib/macro', __FILE__) require File.expand_path('../gollum-lib/file', __FILE__) require File.expand_path('../gollum-lib/file_view', __FILE__) require File.expand_path('../gollum-lib/markup', __FILE__) require File.expand_path('../gollum-lib/markups', __FILE__) require File.expand_path('../gollum-lib/sanitization', __FILE__) require File.expand_path('../gollum-lib/filter', __FILE__) # Set ruby to UTF-8 mode # This is required for Ruby 1.8.7 which gollum still supports. $KCODE = 'U' if RUBY_VERSION[0, 3] == '1.8' module Gollum def self.assets_path ::File.expand_path('gollum/frontend/public', ::File.dirname(__FILE__)) end class Error < StandardError; end class DuplicatePageError < Error attr_accessor :dir attr_accessor :existing_path attr_accessor :attempted_path def initialize(dir, existing, attempted, message = nil) @dir = dir @existing_path = existing @attempted_path = attempted super(message || "Cannot write #{@dir}/#{@attempted_path}, found #{@dir}/#{@existing_path}.") end end class InvalidGitRepositoryError < StandardError; end class NoSuchPathError < StandardError; end end gollum-lib-4.2.7/lib/gollum-lib/0000755000004100000410000000000013172672532016440 5ustar www-datawww-datagollum-lib-4.2.7/lib/gollum-lib/macro.rb0000644000004100000410000000212613172672532020067 0ustar www-datawww-datamodule Gollum class Macro # Find the macro named, create an instance of that, and return it def self.instance(macro_name, wiki, page) begin self.const_get(macro_name).new(wiki, page) rescue NameError Unknown_Macro.new(macro_name) end end def initialize(wiki, page) @wiki = wiki @page = page end def render(*_args) raise ArgumentError, "#{self.class} does not implement #render. "+ "This is a bug in #{self.class}." end protected def html_error(s) "

#{s}

" end # The special class we reserve for only the finest of screwups. The # underscore is to make sure nobody can define a real, callable macro # with the same name, because that would be... exciting. class Unknown_Macro < Macro def initialize(macro_name) @macro_name = macro_name end def render(*_args) "!!!Unknown macro: #{@macro_name}!!!" end end end end Dir[File.expand_path('../macro/*.rb', __FILE__)].each { |f| require f } gollum-lib-4.2.7/lib/gollum-lib/pagination.rb0000644000004100000410000000365113172672532021123 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ module Gollum module Pagination def self.included(klass) klass.extend ClassMethods class << klass # Default Integer max count of items to return in git commands. attr_accessor :per_page end klass.per_page = 30 end module ClassMethods # Turns a page number into an offset number for the git skip option. # # page - Integer page number. # # Returns an Integer. def page_to_skip(page) ([1, page.to_i].max - 1) * per_page end # Fills in git-specific options for the log command using simple # pagination options. # # options - Hash of options: # page - Optional Integer page number (default: 1) # per_page - Optional Integer max count of items to return. # Defaults to #per_class class method. # # Returns Hash with :max_count and :skip keys. def log_pagination_options(options = {}) skip = page_to_skip(options.delete(:page)) options[:max_count] = [options.delete(:per_page).to_i, per_page].max options[:skip] = skip if skip > 0 options end end # Turns a page number into an offset number for the git skip option. # # page - Integer page number. # # Returns an Integer. def page_to_skip(page) self.class.page_to_skip(page) end # Fills in git-specific options for the log command using simple # pagination options. # # options - Hash of options: # page - Optional Integer page number (default: 1) # per_page - Optional Integer max count of items to return. # Defaults to #per_class class method. # # Returns Hash with :max_count and :skip keys. def log_pagination_options(options = {}) self.class.log_pagination_options(options) end end end gollum-lib-4.2.7/lib/gollum-lib/filter/0000755000004100000410000000000013172672532017725 5ustar www-datawww-datagollum-lib-4.2.7/lib/gollum-lib/filter/remote_code.rb0000644000004100000410000000367713172672532022554 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ require 'net/http' require 'net/https' # ruby 1.8.7 fix, remove at upgrade require 'uri' require 'open-uri' # Remote code - fetch code from url and replace the contents to a # code-block that gets run the next parse. # Acceptable formats: # ```language:local-file.ext``` # ```language:/abs/other-file.ext``` # ```language:https://example.com/somefile.txt``` # class Gollum::Filter::RemoteCode < Gollum::Filter def extract(data) return data if @markup.format == :txt data.gsub(/^[ \t]*``` ?([^:\n\r]+):((http)?[^`\n\r]+)```/) do language = Regexp.last_match[1] uri = Regexp.last_match[2] protocol = Regexp.last_match[3] # Detect local file if protocol.nil? if (file = @markup.find_file(uri, @markup.wiki.ref)) contents = file.raw_data else # How do we communicate a render error? next html_error("File not found: #{CGI::escapeHTML(uri)}") end else contents = req(uri) end "```#{language}\n#{contents}\n```\n" end end def process(data) data end private def req(uri, cut = 1) uri = URI(uri) return "Too many redirects or retries" if cut >= 10 http = Net::HTTP.new uri.host, uri.port http.use_ssl = true resp = http.get uri.path, { 'Accept' => 'text/plain', 'Cache-Control' => 'no-cache', 'Connection' => 'keep-alive', 'User-Agent' => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0' } code = resp.code.to_i return resp.body if code == 200 return "Not Found" if code == 404 return "Unhandled Response Code #{code}" unless code == 304 or not resp.header['location'].nil? loc = URI.parse resp.header['location'] uri2 = loc.relative? ? (uri + loc) : loc # overloads (+) req uri2, (cut + 1) end end gollum-lib-4.2.7/lib/gollum-lib/filter/macro.rb0000644000004100000410000000277313172672532021364 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ # Replace specified tokens with dynamically generated content. class Gollum::Filter::Macro < Gollum::Filter def extract(data) quoted_arg = %r{".*?"} unquoted_arg = %r{[^,)]+} named_arg = %r{[a-z0-9_]+=".*?"} arg = %r{(?:#{quoted_arg}|#{unquoted_arg}|#{named_arg})} arg_list = %r{(\s*|#{arg}(?:\s*,\s*#{arg})*)} data.gsub(/('?)\<\<\s*([A-Z][A-Za-z0-9]*)\s*\(#{arg_list}\)\s*\>\>/) do next CGI.escape_html($&[1..-1]) unless Regexp.last_match[1].empty? id = Digest::SHA1.hexdigest(Regexp.last_match[2] + Regexp.last_match[3]) macro = Regexp.last_match[2] argstr = Regexp.last_match[3] args = [] opts = {} argstr.scan(/,?\s*(#{arg})\s*/) do |arguments| # Stabstabstab argument = arguments.first if argument =~ /^([a-z0-9_]+)="(.*?)"/ opts[Regexp.last_match[1]] = Regexp.last_match[2] elsif argument =~ /^"(.*)"$/ args << Regexp.last_match[1] else args << argument end end args << opts unless opts.empty? @map[id] = { :macro => macro, :args => args } id end end def process(data) @map.each do |id, spec| macro = spec[:macro] args = spec[:args] data.gsub!(id) do begin Gollum::Macro.instance(macro, @markup.wiki, @markup.page).render(*args) rescue StandardError => e "!!!Macro Error: #{e.message}!!!" end end end data end end gollum-lib-4.2.7/lib/gollum-lib/filter/emoji.rb0000644000004100000410000000125213172672532021355 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ # Emoji # # Render emoji such as :smile: class Gollum::Filter::Emoji < Gollum::Filter EXTRACT_PATTERN = %r{ (?[\w-]+): (?!\]{^2}) }ix PROCESS_PATTERN = %r{ =EEMMOOJJII= (?[\w-]+) =IIJJOOMMEE= }ix def extract(data) data.gsub! EXTRACT_PATTERN do emoji_exists?($~[:name]) ? "=EEMMOOJJII=#{$~[:name]}=IIJJOOMMEE=" : $& end data end def process(data) data.gsub! PROCESS_PATTERN, %q(\k<name>) data end private def emoji_exists?(name) @index ||= Gemojione::Index.new !!@index.find_by_name(name) end end gollum-lib-4.2.7/lib/gollum-lib/filter/toc.rb0000644000004100000410000001014113172672532021034 0ustar www-datawww-data# Inserts header anchors and creates TOC class Gollum::Filter::TOC < Gollum::Filter def extract(data) data end def process(data) @doc = Nokogiri::HTML::DocumentFragment.parse(data) @toc_doc = nil @anchor_names = {} @current_ancestors = [] toc_str = '' if @markup.sub_page && @markup.parent_page toc_str = @markup.parent_page.toc_data else @doc.css('h1,h2,h3,h4,h5,h6').each_with_index do |header, i| next if header.content.empty? # omit the first H1 (the page title) from the TOC if so configured next if (i == 0 && header.name =~ /[Hh]1/) && @markup.wiki && @markup.wiki.h1_title anchor_name = generate_anchor_name(header) add_anchor_to_header header, anchor_name add_entry_to_toc header, anchor_name end if not @toc_doc.nil? toc_str = @toc_doc.to_xml(@markup.to_xml_opts) end data = @doc.to_xml(@markup.to_xml_opts) end @markup.toc = toc_str data.gsub!(/\[\[_TOC_(.*?)\]\]/) do levels = nil levels_match = Regexp.last_match[1].match /\|\s*levels\s*=\s*(\d+)/ if levels_match levels = levels_match[1].to_i end if levels.nil? || toc_str.empty? toc_str else @toc_doc ||= Nokogiri::HTML::DocumentFragment.parse(toc_str) toc_clone = @toc_doc.clone toc_clone.traverse do |e| if e.name == 'ul' and e.ancestors('ul').length > levels - 1 e.remove end end toc_clone.to_xml(@markup.to_xml_opts) end end data end private # Generates the anchor name from the given header element # removing all non alphanumeric characters, replacing them # with single dashes. # # Generates heading ancestry prefixing the headings # ancestor names to the generated name. # # Prefixes duplicate anchors with an index def generate_anchor_name(header) name = header.content level = header.name.gsub(/[hH]/, '').to_i # normalize the header name name.gsub!(/[^\d\w\u00C0-\u1FFF\u2C00-\uD7FF]/, "-") name.gsub!(/-+/, "-") name.gsub!(/^-/, "") name.gsub!(/-$/, "") name.downcase! @current_ancestors[level - 1] = name @current_ancestors = @current_ancestors.take(level) anchor_name = @current_ancestors.compact.join("_") # Ensure duplicate anchors have a unique prefix or the toc will break index = increment_anchor_index(anchor_name) anchor_name = "#{index}-#{anchor_name}" unless index.zero? # if the index is zero this name is unique anchor_name end # Creates an anchor element with the given name and adds it before # the given header element. def add_anchor_to_header(header, name) anchor_element = %Q() header.children.before anchor_element # Add anchor element before the header end # Adds an entry to the TOC for the given header. The generated entry # is a link to the given anchor name def add_entry_to_toc(header, name) @toc_doc ||= Nokogiri::XML::DocumentFragment.parse('
Table of Contents
') @tail ||= @toc_doc.child @tail_level ||= 0 level = header.name.gsub(/[hH]/, '').to_i if @tail_level < level while @tail_level < level list = Nokogiri::XML::Node.new('ul', @doc) @tail.add_child(list) @tail = list.add_child(Nokogiri::XML::Node.new('li', @doc)) @tail_level += 1 end else while @tail_level > level @tail = @tail.parent.parent @tail_level -= 1 end @tail = @tail.parent.add_child(Nokogiri::XML::Node.new('li', @doc)) end # % -> %25 so anchors work on Firefox. See issue #475 @tail.add_child(%Q{#{header.content}}) end # Increments the number of anchors with the given name # and returns the current index def increment_anchor_index(name) @anchor_names = {} if @anchor_names.nil? @anchor_names[name].nil? ? @anchor_names[name] = 0 : @anchor_names[name] += 1 end end gollum-lib-4.2.7/lib/gollum-lib/filter/plain_text.rb0000644000004100000410000000046213172672532022423 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ # Plain Text # # Render plain text documents in a
 block without any special markup.

class Gollum::Filter::PlainText < Gollum::Filter

  def extract(data)
    @markup.format == :txt ? "
#{CGI.escapeHTML(data)}
" : data end def process(data) data end endgollum-lib-4.2.7/lib/gollum-lib/filter/metadata.rb0000644000004100000410000000206013172672532022030 0ustar www-datawww-data# Extract metadata for data and build metadata table. Metadata consists of # key/value pairs in "key:value" format found between markers. Each # key/value pair must be on its own line. Internal whitespace in keys and # values is preserved, but external whitespace is ignored. # # Because ri and ruby 1.8.7 are awesome, the markers can't # be included in this documentation without triggering # `Unhandled special: Special: type=17` # Please read the source code for the exact markers class Gollum::Filter::Metadata < Gollum::Filter def extract(data) # The markers are `` data.gsub(/\<\!--+\s+---(.*?)--+\>/m) do @markup.metadata ||= {} # Split untrusted input on newlines, then remove bits that look like # HTML elements before parsing each line. Regexp.last_match[1].split("\n").each do |line| line.gsub!(/<[^>]*>/, '') k, v = line.split(':', 2) @markup.metadata[k.strip] = (v ? v.strip : '') if k end '' end end def process(data) data end end gollum-lib-4.2.7/lib/gollum-lib/filter/render.rb0000644000004100000410000000062713172672532021536 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ class Gollum::Filter::Render < Gollum::Filter def extract(data) begin data = GitHub::Markup.render(@markup.name, data) if data.nil? raise "There was an error converting #{@markup.name} to HTML." end rescue Object => e data = html_error("Failed to render page: #{e.message}") end data end def process(data) data end endgollum-lib-4.2.7/lib/gollum-lib/filter/code.rb0000644000004100000410000001126113172672532021165 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ # Code # # Render a block of code using the Rouge syntax-highlighter. class Gollum::Filter::Code < Gollum::Filter def extract(data) case @markup.format when :txt return data when :asciidoc data.gsub!(/^(\[source,([^\r\n]*)\]\n)?----\n(.+?)\n----$/m) do cache_codeblock(Regexp.last_match[2], Regexp.last_match[3]) end when :org org_headers = %r{([ \t]*#\+HEADER[S]?:[^\r\n]*\n)*} org_name = %r{([ \t]*#\+NAME:[^\r\n]*\n)?} org_lang = %r{[ ]*([^\n \r]*)[ ]*[^\r\n]*} org_begin = %r{[ \t]*#\+BEGIN_SRC#{org_lang}\n} org_end = %r{\n[ \t]*#\+END_SRC[ \t]*} data.gsub!(/^#{org_headers}#{org_name}#{org_begin}(.+?)#{org_end}$/mi) do cache_codeblock(Regexp.last_match[3], Regexp.last_match[4]) end when :markdown data.gsub!(/^([ \t]*)(~~~+) ?([^\r\n]+)?\r?\n(.+?)\r?\n\1(~~~+)[ \t\r]*$/m) do m_indent = Regexp.last_match[1] m_start = Regexp.last_match[2] # ~~~ m_lang = Regexp.last_match[3] m_code = Regexp.last_match[4] m_end = Regexp.last_match[5] # ~~~ # start and finish tilde fence must be the same length next '' if m_start.length != m_end.length lang = m_lang ? m_lang.strip : nil if lang lang = lang.match(/\.([^}\s]+)/) lang = lang[1] unless lang.nil? end "#{m_indent}#{cache_codeblock(lang, m_code, m_indent)}" end end data.gsub!(/^([ \t]*)``` ?([^\r\n]+)?\r?\n(.+?)\r?\n\1```[ \t]*\r?$/m) do "#{Regexp.last_match[1]}#{cache_codeblock(Regexp.last_match[2].to_s.strip, Regexp.last_match[3], Regexp.last_match[1])}" # print the SHA1 ID with the proper indentation end data end # Process all code from the codemap and replace the placeholders with the # final HTML. # # data - The String data (with placeholders). # encoding - Encoding Constant or String. # # Returns the marked up String data. def process(data) return data if data.nil? || data.size.zero? || @map.size.zero? blocks = [] @map.each do |_id, spec| next if spec[:output] # cached code = spec[:code] remove_leading_space(code, /^#{spec[:indent]}/m) remove_leading_space(code, /^( |\t)/m) blocks << [spec[:lang], code] end highlighted = [] blocks.each do |lang, code| encoding = @markup.encoding || 'utf-8' if defined? Pygments # Set the default lexer to 'text' to prevent #153 and #154 lang = lang || 'text' lexer = Pygments::Lexer[(lang)] || Pygments::Lexer['text'] # must set startinline to true for php to be highlighted without { :encoding => encoding.to_s, :startinline => true }) else # Rouge begin # if `lang` was not defined then assume plaintext lexer = Rouge::Lexer.find_fancy(lang || 'plaintext') formatter = Rouge::Formatters::HTML.new wrap_template = '
%s
' # if `lang` is defined but cannot be found then wrap it with an error if lexer.nil? lexer = Rouge::Lexers::PlainText wrap_template = '
%s
' end formatted = formatter.format(lexer.lex(code)) hl_code = Kernel.sprintf(wrap_template, formatted) rescue hl_code = code end end highlighted << hl_code end @map.each do |id, spec| body = spec[:output] || begin if (body = highlighted.shift.to_s).size > 0 @markup.update_cache(:code, id, body) body else "
#{CGI.escapeHTML(spec[:code])}
" end end # Removes paragraph tags surrounding
 blocks, see issue https://github.com/gollum/gollum-lib/issues/97
      data.gsub!(/(

#{id}<\/p>|#{id})/) { body } end data end private # Remove the leading space from a code block. Leading space # is only removed if every single line in the block has leading # whitespace. # # code - The code block to remove spaces from # regex - A regex to match whitespace def remove_leading_space(code, regex) if code.lines.all? { |line| line =~ /\A\r?\n\Z/ || line =~ regex } code.gsub!(regex) { '' } end end def cache_codeblock(language, code, indent = "") language = language.to_s.empty? ? nil : language id = Digest::SHA1.hexdigest("#{language}.#{code}") cached = @markup.check_cache(:code, id) @map[id] = cached ? { :output => cached } : { :lang => language, :code => code, :indent => indent } id end end gollum-lib-4.2.7/lib/gollum-lib/filter/tags.rb0000644000004100000410000002305413172672532021214 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ # Render all tags (things in double-square-brackets). This one's a biggie. class Gollum::Filter::Tags < Gollum::Filter # Extract all tags into the tagmap and replace with placeholders. def extract(data) return data if @markup.format == :txt || @markup.format == :asciidoc data.gsub!(/(.?)\[\[(.+?)\]\]([^\[]?)/m) do if Regexp.last_match[1] == "'" && Regexp.last_match[3] != "'" "[[#{Regexp.last_match[2]}]]#{Regexp.last_match[3]}" elsif Regexp.last_match[2].include?('][') if Regexp.last_match[2][0..4] == 'file:' pre = Regexp.last_match[1] post = Regexp.last_match[3] parts = Regexp.last_match[2].split('][') parts[0][0..4] = "" link = "#{parts[1]}|#{parts[0].sub(/\.org/, '')}" id = register_tag(link) "#{pre}#{id}#{post}" else Regexp.last_match[0] end else id = register_tag(Regexp.last_match[2]) "#{Regexp.last_match[1]}#{id}#{Regexp.last_match[3]}" end end data end def register_tag(tag) id = "TAG#{Digest::SHA1.hexdigest(tag)}TAG" @map[id] = tag id end # Process all text nodes from the doc and replace the placeholders with the # final markup. def process(rendered_data) doc = Nokogiri::HTML::DocumentFragment.parse(rendered_data) doc.traverse do |node| if node.text? then content = node.content content.gsub!(/TAG[a-f0-9]+TAG/) do |id| if (tag = @map[id]) then if is_preformatted?(node) then "[[#{tag}]]" else process_tag(tag).gsub('%2f', '/') end end end node.replace(content) if content != node.content end end doc.to_html end private PREFORMATTED_TAGS = %w(code tt) def is_preformatted?(node) node && (PREFORMATTED_TAGS.include?(node.name) || node.ancestors.any? { |a| PREFORMATTED_TAGS.include?(a.name) }) end # Process a single tag into its final HTML form. # # tag - The String tag contents (the stuff inside the double # brackets). # # Returns the String HTML version of the tag. def process_tag(tag) if tag =~ /^_TOC_/ %{[[#{tag}]]} elsif tag =~ /^_$/ %{

} elsif (html = process_include_tag(tag)) html elsif (html = process_image_tag(tag)) html elsif (html = process_external_link_tag(tag)) html elsif (html = process_file_link_tag(tag)) html else process_page_link_tag(tag) end end # Attempt to process the tag as an include tag # # tag - The String tag contents (the stuff inside the double brackets). # # Returns the String HTML if the tag is a valid image tag or nil # if it is not. # def process_include_tag(tag) return unless /^include:/.match(tag) page_name = tag[8..-1] resolved_page_name = ::File.expand_path(page_name, "/"+@markup.dir) if @markup.include_levels > 0 page = find_page_from_name(resolved_page_name) if page page.formatted_data(@markup.encoding, @markup.include_levels-1) else html_error("Cannot include #{process_page_link_tag(resolved_page_name)} - does not exist yet") end else html_error("Too many levels of included pages, will not include #{process_page_link_tag(resolved_page_name)}") end end # Attempt to process the tag as an image tag. # # tag - The String tag contents (the stuff inside the double brackets). # # Returns the String HTML if the tag is a valid image tag or nil # if it is not. def process_image_tag(tag) parts = tag.split('|') return if parts.size.zero? name = parts[0].strip if (file = @markup.find_file(name)) path = ::File.join @markup.wiki.base_path, file.path elsif name =~ /^https?:\/\/.+(jpg|png|gif|svg|bmp)$/i path = name elsif name =~ /.+(jpg|png|gif|svg|bmp)$/i # If is image, file not found and no link, then populate with empty String # We can than add an image not found alt attribute for this later path = "" end if path opts = parse_image_tag_options(tag) containered = false classes = [] # applied to whatever the outermost container is attrs = [] # applied to the image align = opts['align'] if opts['float'] containered = true align ||= 'left' if %w{left right}.include?(align) classes << "float-#{align}" end elsif %w{top texttop middle absmiddle bottom absbottom baseline}.include?(align) attrs << %{align="#{align}"} elsif align if %w{left center right}.include?(align) containered = true classes << "align-#{align}" end end if (width = opts['width']) if width =~ /^\d+(\.\d+)?(em|px)$/ attrs << %{width="#{width}"} end end if (height = opts['height']) if height =~ /^\d+(\.\d+)?(em|px)$/ attrs << %{height="#{height}"} end end if path != "" && (alt = opts['alt']) attrs << %{alt="#{alt}"} elsif path == "" attrs << %{alt="Image not found"} end attr_string = attrs.size > 0 ? attrs.join(' ') + ' ' : '' if opts['frame'] || containered classes << 'frame' if opts['frame'] %{} + %{} + %{} + (alt ? %{#{alt}} : '') + %{} + %{} else %{} end end end # Parse any options present on the image tag and extract them into a # Hash of option names and values. # # tag - The String tag contents (the stuff inside the double brackets). # # Returns the options Hash: # key - The String option name. # val - The String option value or true if it is a binary option. def parse_image_tag_options(tag) tag.split('|')[1..-1].inject({}) do |memo, attr| parts = attr.split('=').map { |x| x.strip } memo[parts[0]] = (parts.size == 1 ? true : parts[1]) memo end end # Return the String HTML if the tag is a valid external link tag or # nil if it is not. def process_external_link_tag(tag) parts = tag.split('|') parts.reverse! if @markup.reverse_links? return if parts.size.zero? if parts.size == 1 url = parts[0].strip else name, url = *parts.compact.map(&:strip) end accepted_protocols = @markup.wiki.sanitization.protocols['a']['href'].dup if accepted_protocols.include?(:relative) accepted_protocols.select!{|protocol| protocol != :relative} regexp = %r{^((#{accepted_protocols.join("|")}):)?(//)} else regexp = %r{^((#{accepted_protocols.join("|")}):)} end if url =~ regexp if name.nil? %{#{url}} else %{#{name}} end else nil end end # Attempt to process the tag as a file link tag. # # tag - The String tag contents (the stuff inside the double # brackets). # # Returns the String HTML if the tag is a valid file link tag or nil # if it is not. def process_file_link_tag(tag) parts = tag.split('|') return if parts.size.zero? name = parts[0].strip path = parts[1] && parts[1].strip if path && file = @markup.find_file(path) path = ::File.join @markup.wiki.base_path, file.path else path = nil end if name && path && file %{#{name}} elsif name && path %{#{name}} else nil end end # Attempt to process the tag as a page link tag. # # tag - The String tag contents (the stuff inside the double # brackets). # # Returns the String HTML if the tag is a valid page link tag or nil # if it is not. def process_page_link_tag(tag) parts = tag.split('|') parts.reverse! if @markup.reverse_links? name, page_name = *parts.compact.map(&:strip) cname = @markup.wiki.page_class.cname(page_name || name) presence = "absent" link_name = cname page, extra = find_page_from_name(cname) if page link_name = @markup.wiki.page_class.cname(page.name) presence = "present" end link = ::File.join(@markup.wiki.base_path, page ? page.escaped_url_path : CGI.escape(link_name)) # //page is invalid # strip all duplicate forward slashes using helpers.rb trim_leading_slash # //page => /page link = trim_leading_slash link %{#{name}} end # Find a page from a given cname. If the page has an anchor (#) and has # no match, strip the anchor and try again. # # cname - The String canonical page name including path. # # Returns a Gollum::Page instance if a page is found, or an Array of # [Gollum::Page, String extra] if a page without the extra anchor data # is found. def find_page_from_name(cname) slash = cname.rindex('/') unless slash.nil? name = cname[slash+1..-1] path = cname[0..slash] page = @markup.wiki.paged(name, path) else page = @markup.wiki.paged(cname, '/') || @markup.wiki.page(cname) end if page return page end if (pos = cname.index('#')) [@markup.wiki.page(cname[0...pos]), cname[pos..-1]] end end end gollum-lib-4.2.7/lib/gollum-lib/filter/plantuml.rb0000644000004100000410000001061413172672532022110 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ require 'net/http' require 'uri' require 'open-uri' require 'zlib' # PlantUML Diagrams # # This filter replaces PlantUML blocks with HTML img tags. These img tags # point to a PlantUML web service that converts the UML text blocks into nice # diagrams. # # For this to work you must have your own PlantUML server running somewhere. # Just follow the instructions on the github page to run your own server: # # https://github.com/plantuml/plantuml-server # # Once you start you own plantuml server you need to configure this filter to # point to it: # # Gollum::Filter::PlantUML.configure do |config| # config.url = "http://localhost:8080/plantuml/png" # end # # Then in your wiki pages simply add PlantUML blocks anywhere you want a # diagram: # # @startuml # Alice -> Bob: Authentication Request # Bob --> Alice: Authentication Response # Alice -> Bob: Another authentication Request # Alice <-- Bob: another authentication Response # @enduml # # To learn more about how to create cool PlantUML diagrams check the examples # at: http://plantuml.sourceforge.net/ # class Gollum::Filter::PlantUML < Gollum::Filter DEFAULT_URL = "http://localhost:8080/plantuml/png" # Configuration class used to change the behaviour of the PlatnUML filter. # # url: PlantUML server URL (e.g. http://localhost:8080) # test: Set to true when running tests to skip the server check. # class Configuration attr_accessor :url, :test, :verify_ssl def initialize @url = DEFAULT_URL @verify_ssl = true @test = false end end class << self attr_writer :configuration end def self.configuration @configuration ||= Configuration.new end def self.configure yield(configuration) end # Extract all sequence diagram blocks into the map and replace with # placeholders. def extract(data) return data if @markup.format == :txt data.gsub(/(@startuml\r?\n.+?\r?\n@enduml\r?$)/m) do id = Digest::SHA1.hexdigest($1) @map[id] = { :code => $1 } id end end # Process all diagrams from the map and replace the placeholders with # the final HTML. def process(data) @map.each do |id, spec| data.gsub!(id) do render_plantuml(id, spec[:code]) end end data end private def server_url PlantUML::configuration.url end def test? PlantUML::configuration.test end def verify_ssl? PlantUML::configuration.verify_ssl end def render_plantuml(id, code) if check_server plantuml_url = gen_url(code) "" else html_error("Sorry, unable to render PlantUML diagram at this time") end end # Compression code used to generate PlantUML URLs. Taken directly from the # Transcoder class in the PlantUML java code. def gen_url(text) result = "" compressedData = Zlib::Deflate.deflate(text) compressedData.chars.each_slice(3) do |bytes| #print bytes[0], ' ' , bytes[1] , ' ' , bytes[2] b1 = bytes[0].nil? ? 0 : (bytes[0].ord & 0xFF) b2 = bytes[1].nil? ? 0 : (bytes[1].ord & 0xFF) b3 = bytes[2].nil? ? 0 : (bytes[2].ord & 0xFF) result += append3bytes(b1, b2, b3) end "#{server_url}/#{result}" end def encode6bit(b) if b < 10 return ('0'.ord + b).chr end b = b - 10 if b < 26 return ('A'.ord + b).chr end b = b - 26 if b < 26 return ('a'.ord + b).chr end b = b - 26 if b == 0 return '-' end if b == 1 return '_' end return '?' end def append3bytes(b1, b2, b3) c1 = b1 >> 2 c2 = ((b1 & 0x3) << 4) | (b2 >> 4) c3 = ((b2 & 0xF) << 2) | (b3 >> 6) c4 = b3 & 0x3F return encode6bit(c1 & 0x3F).chr + encode6bit(c2 & 0x3F).chr + encode6bit(c3 & 0x3F).chr + encode6bit(c4 & 0x3F).chr end # Make a call to the PlantUML server with the simplest diagram possible to # check if the server is available or not. def check_server return true if test? check_url = "#{server_url}/SyfFKj2rKt3CoKnELR1Io4ZDoSa70000" uri = URI.parse(check_url) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true if uri.scheme == 'https' http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless verify_ssl? response = http.request_get(uri.request_uri) return response.is_a?(Net::HTTPSuccess) rescue return false end end gollum-lib-4.2.7/lib/gollum-lib/filter/sanitize.rb0000644000004100000410000000051713172672532022103 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ class Gollum::Filter::Sanitize < Gollum::Filter def extract(data) data end def process(data) if @markup.sanitize doc = Nokogiri::HTML::DocumentFragment.parse(data) doc = @markup.sanitize.clean_node!(doc) doc.to_xml(@markup.to_xml_opts) else data end end end gollum-lib-4.2.7/lib/gollum-lib/filter/wsd.rb0000644000004100000410000000307713172672532021056 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ require 'net/http' require 'uri' require 'open-uri' # Web Sequence Diagrams # # Render an inline web sequence diagram by sending the WSD code through the # online renderer available from www.websequencediagrams.com. # class Gollum::Filter::WSD < Gollum::Filter WSD_URL = "http://www.websequencediagrams.com/index.php" # Extract all sequence diagram blocks into the map and replace with # placeholders. def extract(data) return data if @markup.format == :txt data.gsub(/^\{\{\{\{\{\{ ?(.+?)\r?\n(.+?)\r?\n\}\}\}\}\}\}\r?$/m) do id = Digest::SHA1.hexdigest(Regexp.last_match[2]) @map[id] = { :style => Regexp.last_match[1], :code => Regexp.last_match[2] } id end end # Process all diagrams from the map and replace the placeholders with # the final HTML. # # data - The String data (with placeholders). # # Returns the marked up String data. def process(data) @map.each do |id, spec| data.gsub!(id) do render_wsd(spec[:code], spec[:style]) end end data end private # Render the sequence diagram on the remote server. # # Returns an tag to the rendered image, or an HTML error. def render_wsd(code, style) response = Net::HTTP.post_form(URI.parse(WSD_URL), 'style' => style, 'message' => code) if response.body =~ /img: "(.+)"/ url = "//www.websequencediagrams.com/#{Regexp.last_match[1]}" "" else puts response.body html_error("Sorry, unable to render sequence diagram at this time.") end end end gollum-lib-4.2.7/lib/gollum-lib/sanitization.rb0000644000004100000410000001362613172672532021511 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ module Gollum # Encapsulate sanitization options. # # This class does not yet support all options of Sanitize library. # See http://github.com/rgrove/sanitize/. class Sanitization # Default whitelisted elements. ELEMENTS = [ 'a', 'abbr', 'acronym', 'address', 'area', 'b', 'big', 'blockquote', 'br', 'button', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'dir', 'div', 'dl', 'dt', 'em', 'fieldset', 'font', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'map', 'mark', 'menu', 'ol', 'optgroup', 'option', 'p', 'pre', 'q', 's', 'samp', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var' ].freeze # Default whitelisted attributes. ATTRIBUTES = { 'a' => ['href'], 'img' => ['src'], :all => ['abbr', 'accept', 'accept-charset', 'accesskey', 'action', 'align', 'alt', 'axis', 'border', 'cellpadding', 'cellspacing', 'char', 'charoff', 'class', 'charset', 'checked', 'cite', 'clear', 'cols', 'colspan', 'color', 'compact', 'coords', 'datetime', 'dir', 'disabled', 'enctype', 'for', 'frame', 'headers', 'height', 'hreflang', 'hspace', 'id', 'ismap', 'label', 'lang', 'longdesc', 'maxlength', 'media', 'method', 'multiple', 'name', 'nohref', 'noshade', 'nowrap', 'prompt', 'readonly', 'rel', 'rev', 'rows', 'rowspan', 'rules', 'scope', 'selected', 'shape', 'size', 'span', 'start', 'summary', 'tabindex', 'target', 'title', 'type', 'usemap', 'valign', 'value', 'vspace', 'width'] }.freeze # Default whitelisted protocols for URLs. PROTOCOLS = { 'a' => { 'href' => ['http', 'https', 'mailto', 'ftp', 'irc', 'apt', :relative] }, 'img' => { 'src' => ['http', 'https', :relative] }, 'form' => { 'action' => ['http', 'https', :relative] } }.freeze ADD_ATTRIBUTES = lambda do |env, node| if (add = env[:config][:add_attributes][node.name]) add.each do |key, value| node[key] = value end end end # Default elements whose contents will be removed in addition # to the elements themselve REMOVE_CONTENTS = [ 'script', 'style' ].freeze # Default transformers to force @id attributes with 'wiki-' prefix TRANSFORMERS = [ lambda do |env| node = env[:node] return if env[:is_whitelisted] || !node.element? prefix = env[:config][:id_prefix] found_attrs = %w(id name).select do |key| if (value = node[key]) node[key] = value.gsub(/\A(#{prefix})?/, prefix) end end if found_attrs.size > 0 ADD_ATTRIBUTES.call(env, node) {} end end, lambda do |env| node = env[:node] return unless (value = node['href']) prefix = env[:config][:id_prefix] node['href'] = value.gsub(/\A\#(#{prefix})?/, '#'+prefix) ADD_ATTRIBUTES.call(env, node) {} end ].freeze # Gets an Array of whitelisted HTML elements. Default: ELEMENTS. attr_reader :elements # Gets a Hash describing which attributes are allowed in which HTML # elements. Default: ATTRIBUTES. attr_reader :attributes # Gets a Hash describing which URI protocols are allowed in HTML # attributes. Default: PROTOCOLS attr_reader :protocols # Gets a Hash describing which URI protocols are allowed in HTML # attributes. Default: TRANSFORMERS attr_reader :transformers # Gets or sets a String prefix which is added to ID attributes. # Default: '' attr_accessor :id_prefix # Gets a Hash describing HTML attributes that Sanitize should add. # Default: {} attr_reader :add_attributes # Gets an Array of element names whose contents will be removed in addition # to the elements themselves. Default: REMOVE_CONTENTS attr_reader :remove_contents # Sets a boolean determining whether Sanitize allows HTML comments in the # output. Default: false. attr_writer :allow_comments def initialize @elements = ELEMENTS.dup @attributes = ATTRIBUTES.dup @protocols = PROTOCOLS.dup @transformers = TRANSFORMERS.dup @add_attributes = {} @remove_contents = REMOVE_CONTENTS.dup @allow_comments = false @id_prefix = '' yield self if block_given? end # Determines if Sanitize should allow HTML comments. # # Returns True if comments are allowed, or False. def allow_comments? !!@allow_comments end # Modifies the current Sanitization instance to sanitize older revisions # of pages. # # Returns a Sanitization instance. def history_sanitization self.class.new do |sanitize| sanitize.add_attributes['a'] = { 'rel' => 'nofollow' } end end # Builds a Hash of options suitable for Sanitize.clean. # # Returns a Hash. def to_hash { :elements => elements, :attributes => attributes, :protocols => protocols, :add_attributes => add_attributes, :remove_contents => remove_contents, :allow_comments => allow_comments?, :transformers => transformers, :id_prefix => id_prefix } end # Builds a Sanitize instance from the current options. # # Returns a Sanitize instance. def to_sanitize Sanitize.new(to_hash) end end end gollum-lib-4.2.7/lib/gollum-lib/blob_entry.rb0000644000004100000410000000512713172672532021131 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ module Gollum class BlobEntry # Gets the String SHA for this blob. attr_reader :sha # Gets the full path String for this blob. attr_reader :path # Gets the Fixnum size of this blob. attr_reader :size # Gets the Fixnum mode of this blob. attr_reader :mode def initialize(sha, path, size = nil, mode = nil) @sha = sha @path = path @size = size @mode = mode @dir = @name = @blob = nil end # Gets the normalized directory path String for this blob. def dir @dir ||= self.class.normalize_dir(::File.dirname(@path)) end # Gets the file base name String for this blob. def name @name ||= ::File.basename(@path) end # Gets a Gollum::Git::Blob instance for this blob. # # repo - Gollum::Git::Repo instance for the Gollum::Git::Blob. # # Returns an unbaked Gollum::Git::Blob instance. def blob(repo) @blob ||= Gollum::Git::Blob.create(repo, :id => @sha, :name => name, :size => @size, :mode => @mode) end # Gets a Page instance for this blob. # # wiki - Gollum::Wiki instance for the Gollum::Page # # Returns a Gollum::Page instance. def page(wiki, commit) blob = self.blob(wiki.repo) page = wiki.page_class.new(wiki).populate(blob, self.dir) page.version = commit page end # Gets a File instance for this blob. # # wiki - Gollum::Wiki instance for the Gollum::File # # Returns a Gollum::File instance. def file(wiki, commit) blob = self.blob(wiki.repo) file = wiki.file_class.new(wiki).populate(blob, self.dir) file.version = commit file end def inspect %(#) end # Normalizes a given directory name for searching through tree paths. # Ensures that a directory begins with a slash, or # # normalize_dir("") # => "" # normalize_dir(".") # => "" # normalize_dir("foo") # => "/foo" # normalize_dir("/foo/") # => "/foo" # normalize_dir("/") # => "" # normalize_dir("c:/") # => "" # # dir - String directory name. # # Returns a normalized String directory name, or nil if no directory # is given. def self.normalize_dir(dir) return '' if dir =~ /^.:\/$/ if dir dir = ::File.expand_path(dir, '/') dir = dir[2..-1] if dir =~ /^[a-zA-Z]:\// # expand_path may add d:/ on windows dir = '' if dir == '/' end dir end end end gollum-lib-4.2.7/lib/gollum-lib/hook.rb0000644000004100000410000000126213172672532017726 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ module Gollum class Hook @hooks = {} class << self def register(type, id, &block) type_hooks = @hooks[type] ||= {} type_hooks[id] = block end def unregister(type, id) type_hooks = @hooks[type] if type_hooks type_hooks.delete(id) @hooks.delete(type) if type_hooks.empty? end end def get(type, id) @hooks.fetch(type, {})[id] end def execute(type, *args) type_hooks = @hooks[type] if type_hooks type_hooks.each_value do |block| block.call(*args) end end end end end end gollum-lib-4.2.7/lib/gollum-lib/filter.rb0000644000004100000410000000553113172672532020256 0ustar www-datawww-data# A "filter", in Gollum-speak, is an object which extracts tokens from an # input stream of an arbitrary markup language, then replaces them with a # final form in a rendered form of the same document. Filters are composed # into a "filter chain", which forms the order in which filters are applied # in both the extraction and processing phases (processing happens in the # reverse order to extraction). A single instance of a filter class is used # for both the extraction and processing, so you can store internal state # from the extraction phase for use in the processing phase. # # Any class which is to be used as a filter must have an `initialize` method # which takes a single mandatory argument (the instance of the `Markup` # class we're being called from), and must implement two methods: `extract` # and `process`, both of which must take a string as input and return a # (possibly modified) form of that string as output. # # An example rendering session: consider a filter chain with three filters # in it, :A, :B, and :C (filter chains are specified as symbols, which are # taken to be class names within the Gollum::Filter namespace). An # equivalent of the following will take place: # # a = Gollum::Filter.const_get(:A).new # b = Gollum::Filter.const_get(:B).new # c = Gollum::Filter.const_get(:C).new # # data = "" # # data = a.extract(data) # data = b.extract(data) # data = c.extract(data) # # data = c.process(data) # data = b.process(data) # data = a.process(data) # # # `data` now contains the rendered document, ready for processing # # Note how the extraction steps go in the order of the filter chain, while # the processing steps go in the reverse order. There hasn't (yet) been a # case where that is a huge problem. # # If your particular filter doesn't need to do something with either the # original markup or rendered forms, you can simply define the relevant # method to be a pass-through (`def extract(d) d; end`), but you *must* # define both methods yourself. # module Gollum class Filter include Gollum::Helpers # Setup the object. Sets `@markup` to be the instance of Gollum::Markup that # is running this filter chain, and sets `@map` to be an empty hash (for use # in your extract/process operations). def initialize(markup) @markup = markup @map = {} end def extract(_d) raise RuntimeError, "#{self.class} has not implemented ##extract!" end def process(_d) raise RuntimeError, "#{self.class} has not implemented ##process!" end protected # Render a (presumably) non-fatal error as HTML # def html_error(message) "

#{message}

" end end end # Load all standard filters Dir[File.expand_path('../filter/*.rb', __FILE__)].each { |f| require f } gollum-lib-4.2.7/lib/gollum-lib/file_view.rb0000644000004100000410000001102413172672532020734 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ module Gollum # FileView requires that: # - All files in root dir are processed first # - Then all the folders are sorted and processed class FileView # common use cases: # set pages to wiki.pages and show_all to false # set pages to wiki.pages + wiki.files and show_all to true def initialize(pages, options = {}) @pages = pages @show_all = options[:show_all] || false @checked = options[:collapse_tree] ? '' : "checked" end def enclose_tree(string) %Q(
    \n) + string + %Q(
) end def new_page(page) name = page.name url, valid_page = url_for_page page %Q(
  • #{name}#{valid_page ? "" : delete_file(url, valid_page)}
  • ) end def delete_file(url, valid_page) %Q(
    ) end def new_folder(folder_path) new_sub_folder folder_path end def new_sub_folder(path) <<-HTML
    1. HTML end def end_folder "
  • \n" end def url_for_page(page) url = '' valid_page_name = false if @show_all # Remove ext for valid pages. filename = page.filename valid_page_name = Page::valid_page_name?(filename) filename = valid_page_name ? filename.chomp(::File.extname(filename)) : filename url = ::File.join(::File.dirname(page.path), filename) else url = ::File.join(::File.dirname(page.path), page.filename_stripped) end url = url[2..-1] if url[0, 2] == './' return url, valid_page_name end def render_files html = '' count = @pages.size folder_start = -1 # Process all pages until folders start count.times do |index| page = @pages[index] path = page.path unless path.include? '/' # Page processed (not contained in a folder) html += new_page page else # Folders start at the next index folder_start = index break # Pages finished, move on to folders end end # If there are no folders, then we're done. return enclose_tree(html) if folder_start <= -1 # Handle special case of only one folder. if (count - folder_start == 1) page = @pages[folder_start] html += <<-HTML
    1. #{new_page page}
  • HTML return enclose_tree html end sorted_folders = [] (folder_start).upto count - 1 do |index| sorted_folders += [[@pages[index].path, index]] end # http://stackoverflow.com/questions/3482814/sorting-list-of-string-paths-in-vb-net sorted_folders.sort! do |first, second| a = first[0] b = second[0] # use :: operator because gollum defines its own conflicting File class dir_compare = ::File.dirname(a) <=> ::File.dirname(b) # Sort based on directory name unless they're equal (0) in # which case sort based on file name. if dir_compare == 0 ::File.basename(a) <=> ::File.basename(b) else dir_compare end end # keep track of folder depth, 0 = at root. cwd_array = [] changed = false # process rest of folders (0...sorted_folders.size).each do |i| page = @pages[sorted_folders[i][1]] path = page.path folder = ::File.dirname path tmp_array = folder.split '/' (0...tmp_array.size).each do |index| if cwd_array[index].nil? || changed html += new_sub_folder tmp_array[index] next end if cwd_array[index] != tmp_array[index] changed = true (cwd_array.size - index).times do html += end_folder end html += new_sub_folder tmp_array[index] end end html += new_page page cwd_array = tmp_array changed = false end # return the completed html enclose_tree html end # end render_files end # end FileView class end # end Gollum module gollum-lib-4.2.7/lib/gollum-lib/file.rb0000644000004100000410000001043713172672532017711 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ module Gollum class File Wiki.file_class = self # Public: Initialize a file. # # wiki - The Gollum::Wiki in question. # # Returns a newly initialized Gollum::File. def initialize(wiki) @wiki = wiki @blob = nil @path = nil @on_disk = false @on_disk_path = nil end # Public: The url path required to reach this page within the repo. # # Returns the String url_path def url_path path = self.path path = path.sub(/\/[^\/]+$/, '/') if path.include?('/') path end # Public: The url_path, but CGI escaped. # # Returns the String url_path def escaped_url_path CGI.escape(self.url_path).gsub('%2F', '/') end # Public: The on-disk filename of the file. # # Returns the String name. def name return @path if on_disk? @blob && @blob.name end alias filename name # Public: The raw contents of the page. # # Returns the String data. def raw_data return IO.read(@on_disk_path) if on_disk? return nil unless @blob if !@wiki.repo.bare && @blob.is_symlink new_path = @blob.symlink_target(::File.join(@wiki.repo.path, '..', self.path)) return IO.read(new_path) if new_path end @blob.data end # Public: Is this an on-disk file reference? # # Returns true if this is a pointer to an on-disk file def on_disk? @on_disk end # Public: The path to this file on disk # # Returns nil if on_disk? is false. def on_disk_path @on_disk_path end # Public: The Gollum::Git::Commit version of the file. attr_accessor :version # Public: The String path of the file. attr_reader :path # Public: The String mime type of the file. def mime_type @blob && @blob.mime_type end # Populate the File with information from the Blob. # # blob - The Gollum::Git::Blob that contains the info. # path - The String directory path of the file. # # Returns the populated Gollum::File. def populate(blob, path = nil) @blob = blob @path = "#{path}/#{blob.name}"[1..-1] @on_disk = false @on_disk_path = nil self end ######################################################################### # # Internal Methods # ######################################################################### # Return the file path to this file on disk, if available. # # Returns nil if the file isn't available on disk. This can occur if the # repo is bare, if the commit isn't the HEAD, or if there are problems # resolving symbolic links. def get_disk_reference(name, commit) return false if @wiki.repo.bare return false if commit.sha != @wiki.repo.head.commit.sha # This will try to resolve symbolic links, as well pathname = Pathname.new(::File.expand_path(::File.join(@wiki.repo.path, '..', name))) if pathname.symlink? source = ::File.readlink(pathname.to_path) realpath = ::File.join(::File.dirname(pathname.to_path), source) return false unless realpath && ::File.exist?(realpath) @on_disk_path = realpath.to_s else @on_disk_path = pathname.to_path end true end # Find a file in the given Gollum repo. # # name - The full String path. # version - The String version ID to find. # try_on_disk - If true, try to return just a reference to a file # that exists on the disk. # # Returns a Gollum::File or nil if the file could not be found. Note # that if you specify try_on_disk=true, you may or may not get a file # for which on_disk? is actually true. def find(name, version, try_on_disk = false) checked = name.downcase map = @wiki.tree_map_for(version) commit = version.is_a?(Gollum::Git::Commit) ? version : @wiki.commit_for(version) if (result = map.detect { |entry| entry.path.downcase == checked }) @path = name @version = commit if try_on_disk && get_disk_reference(name, commit) @on_disk = true else @blob = result.blob(@wiki.repo) end self end end end end gollum-lib-4.2.7/lib/gollum-lib/helpers.rb0000644000004100000410000000035413172672532020431 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ module Gollum module Helpers def trim_leading_slash(url) return url if url.nil? url.gsub!('%2F', '/') return '/' + url.gsub(/^\/+/, '') if url[0, 1] == '/' url end end end gollum-lib-4.2.7/lib/gollum-lib/version.rb0000644000004100000410000000007313172672532020452 0ustar www-datawww-datamodule Gollum module Lib VERSION = '4.2.7' end end gollum-lib-4.2.7/lib/gollum-lib/wiki.rb0000644000004100000410000010562113172672532017735 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ module Gollum class Wiki include Pagination class << self # Sets the page class used by all instances of this Wiki. attr_writer :page_class # 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_classes # Sets the default ref for the wiki. attr_writer :default_ref # Sets the default name for commits. attr_writer :default_committer_name # Sets the default email for commits. attr_writer :default_committer_email # Array of chars to substitute whitespace for when trying to locate file in git repo. attr_writer :default_ws_subs # Sets sanitization options. Set to false to deactivate # sanitization altogether. attr_writer :sanitization # Sets sanitization options. Set to false to deactivate # sanitization altogether. attr_writer :history_sanitization # Hash for setting different default wiki options # These defaults can be overridden by options passed directly to initialize() attr_writer :default_options # Gets the page class used by all instances of this Wiki. # Default: Gollum::Page. def page_class @page_class || if superclass.respond_to?(:page_class) superclass.page_class else ::Gollum::Page end end # Gets the file class used by all instances of this Wiki. # Default: Gollum::File. def file_class @file_class || if superclass.respond_to?(:file_class) superclass.file_class else ::Gollum::File end end # Gets the markup class used by all instances of this Wiki. # Default: Gollum::Markup def markup_classes @markup_classes ||= if superclass.respond_to?(:markup_classes) superclass.markup_classes else Hash.new(::Gollum::Markup) end end # Gets the default markup class used by all instances of this Wiki. # Kept for backwards compatibility until Gollum v2.x def markup_class(language=:default) markup_classes[language] end # Sets the default markup class used by all instances of this Wiki. # Kept for backwards compatibility until Gollum v2.x def markup_class=(default) @markup_classes = Hash.new(default).update(markup_classes) default end alias_method :default_markup_class, :markup_class alias_method :default_markup_class=, :markup_class= # Gets the default sanitization options for current pages used by # instances of this Wiki. def sanitization if @sanitization.nil? @sanitization = Sanitization.new end @sanitization end # Gets the default sanitization options for older page revisions used by # instances of this Wiki. def history_sanitization if @history_sanitization.nil? @history_sanitization = sanitization ? sanitization.history_sanitization : false end @history_sanitization end def default_ref @default_ref || 'master' end def default_committer_name @default_committer_name || 'Anonymous' end def default_committer_email @default_committer_email || 'anon@anon.com' end def default_ws_subs @default_ws_subs || ['_', '-'] end def default_options @default_options || {} end end # The String base path to prefix to internal links. For example, when set # to "/wiki", the page "Hobbit" will be linked as "/wiki/Hobbit". Defaults # to "/". attr_reader :base_path # Gets the sanitization options for current pages used by this Wiki. attr_reader :sanitization # Gets the sanitization options for older page revisions used by this Wiki. attr_reader :history_sanitization # Gets the String ref in which all page files reside. attr_reader :ref # Gets the String directory in which all page files reside. attr_reader :page_file_dir # Gets the Array of chars to sub for ws in filenames. attr_reader :ws_subs # Gets the boolean live preview value. attr_reader :live_preview # Injects custom css from custom.css in root repo. # Defaults to false attr_reader :css # Sets page title to value of first h1 # Defaults to false attr_reader :h1_title # Gets the custom index page for / and subdirs (e.g. foo/) attr_reader :index_page # Gets side on which the sidebar should be shown attr_reader :bar_side # An array of symbols which refer to classes under Gollum::Filter, # each of which is an element in the "filtering chain". See # the documentation for Gollum::Filter for more on how this chain # works, and what filter classes need to implement. attr_reader :filter_chain # Public: Initialize a new Gollum Repo. # # path - The String path to the Git repository that holds the Gollum # site. # options - Optional Hash: # :universal_toc - Table of contents on all pages. Default: false # :live_preview - Livepreview editing for markdown files. Default: true # :base_path - String base path for all Wiki links. # Default: "/" # :page_class - The page Class. Default: Gollum::Page # :file_class - The file Class. Default: Gollum::File # :markup_classes - A hash containing the markup Classes for each # document type. Default: { Gollum::Markup } # :sanitization - An instance of Sanitization. # :page_file_dir - String the directory in which all page files reside # :ref - String the repository ref to retrieve pages from # :ws_subs - Array of chars to sub for ws in filenames. # :mathjax - Set to false to disable mathjax. # :user_icons - Enable user icons on the history page. [gravatar, identicon, none]. # Default: none # :show_all - Show all files in file view, not just valid pages. # Default: false # :collapse_tree - Start with collapsed file view. Default: false # :css - Include the custom.css file from the repo. # :emoji - Parse and interpret emoji tags (e.g. :heart:). # :h1_title - Concatenate all h1's on a page to form the # page title. # :index_page - The default page to retrieve or create if the # a directory is accessed. # :bar_side - Where the sidebar should be displayed, may be: # - :left # - :right # :allow_uploads - Set to true to allow file uploads. # :per_page_uploads - Whether uploads should be stored in a central # 'uploads' directory, or in a directory named for # the page they were uploaded to. # :filter_chain - Override the default filter chain with your own. # # Returns a fresh Gollum::Repo. def initialize(path, options = {}) options = self.class.default_options.merge(options) if path.is_a?(GitAccess) options[:access] = path path = path.path end # Use .fetch instead of || # # o = { :a => false } # o[:a] || true # => true # o.fetch :a, true # => false @path = path @repo_is_bare = options.fetch :repo_is_bare, nil @page_file_dir = options.fetch :page_file_dir, nil @access = options.fetch :access, GitAccess.new(path, @page_file_dir, @repo_is_bare) @base_path = options.fetch :base_path, "/" @page_class = options.fetch :page_class, self.class.page_class @file_class = options.fetch :file_class, self.class.file_class @markup_classes = options.fetch :markup_classes, self.class.markup_classes @repo = @access.repo @ref = options.fetch :ref, self.class.default_ref @sanitization = options.fetch :sanitization, self.class.sanitization @ws_subs = options.fetch :ws_subs, self.class.default_ws_subs @history_sanitization = options.fetch :history_sanitization, self.class.history_sanitization @live_preview = options.fetch :live_preview, true @universal_toc = options.fetch :universal_toc, false @mathjax = options.fetch :mathjax, false @show_all = options.fetch :show_all, false @collapse_tree = options.fetch :collapse_tree, false @css = options.fetch :css, false @emoji = options.fetch :emoji, false @h1_title = options.fetch :h1_title, false @index_page = options.fetch :index_page, 'Home' @bar_side = options.fetch :sidebar, :right @user_icons = ['gravatar', 'identicon'].include?(options[:user_icons]) ? options[:user_icons] : 'none' @allow_uploads = options.fetch :allow_uploads, false @per_page_uploads = options.fetch :per_page_uploads, false @filter_chain = options.fetch :filter_chain, [:Metadata, :PlainText, :TOC, :RemoteCode, :Code, :Macro, :Emoji, :Sanitize, :WSD, :PlantUML, :Tags, :Render] @filter_chain.delete(:Emoji) unless options.fetch :emoji, false 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? @access.exist? end # Public: Get the formatted page for a given page name, version, and dir. # # name - The human or canonical String page name of the wiki page. # version - The String version ID to find (default: @ref). # dir - The directory String relative to the repo. # # Returns a Gollum::Page or nil if no matching page was found. def page(name, version = @ref, dir = nil, exact = false) version = @ref if version.nil? @page_class.new(self).find(name, version, dir, exact) end # Public: Convenience method instead of calling page(name, nil, dir). # # name - The human or canonical String page name of the wiki page. # version - The String version ID to find (default: @ref). # dir - The directory String relative to the repo. # # Returns a Gollum::Page or nil if no matching page was found. def paged(name, dir = nil, exact = false, version = @ref) page(name, version, dir, exact) end # Public: Get the static file for a given name. # # name - The full String pathname to the file. # version - The String version ID to find (default: @ref). # try_on_disk - If true, try to return just a reference to a file # that exists on the disk. # # Returns a Gollum::File or nil if no matching file was found. Note # that if you specify try_on_disk=true, you may or may not get a file # for which on_disk? is actually true. def file(name, version = @ref, try_on_disk = false) @file_class.new(self).find(name, version, try_on_disk) end # Public: Create an in-memory Page with the given data and format. This # is useful for previewing what content will look like before committing # it to the repository. # # name - The String name of the page. # format - The Symbol format of the page. # data - The new String contents of the page. # # Returns the in-memory Gollum::Page. def preview_page(name, data, format) page = @page_class.new(self) ext = @page_class.format_to_ext(format.to_sym) name = @page_class.cname(name) + '.' + ext blob = OpenStruct.new(:name => name, :data => data, :is_symlink => false) page.populate(blob) page.version = @access.commit(@ref) page end # Public: Write a new version of a page to the Gollum repo root. # # name - The String name of the page. # 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. # :parent - Optional Gollum::Git::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. # dir - The String subdirectory of the Gollum::Page without any # prefix or suffix slashes (e.g. "foo/bar"). # 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 = {}, dir = '') # spaces must be dashes sanitized_name = name.gsub(' ', '-') sanitized_dir = dir.gsub(' ', '-') sanitized_dir = ::File.join([@page_file_dir, sanitized_dir].compact) multi_commit = !!commit[:committer] committer = multi_commit ? commit[:committer] : Committer.new(self, commit) filename = Gollum::Page.cname(sanitized_name) committer.add_to_index(sanitized_dir, filename, format, data) committer.after_commit do |index, _sha| @access.refresh index.update_working_dir(sanitized_dir, filename, format) end multi_commit ? committer : committer.commit end # Public: Rename an existing page without altering content. # # page - The Gollum::Page to update. # rename - The String extension-less full path of the page (leading '/' is ignored). # commit - The commit Hash details: # :message - The String commit message. # :name - The String author full name. # :email - The String email address. # :parent - Optional Gollum::Git::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, or the # Gollum::Committer instance if this is part of a batch update. # Returns false if the operation is a NOOP. def rename_page(page, rename, commit = {}) return false if page.nil? return false if rename.nil? or rename.empty? (target_dir, target_name) = ::File.split(rename) (source_dir, source_name) = ::File.split(page.path) source_name = page.filename_stripped # File.split gives us relative paths with ".", commiter.add_to_index doesn't like that. target_dir = '' if target_dir == '.' source_dir = '' if source_dir == '.' target_dir = target_dir.gsub(/^\//, '') # if the rename is a NOOP, abort if source_dir == target_dir and source_name == target_name return false end multi_commit = !!commit[:committer] committer = multi_commit ? commit[:committer] : Committer.new(self, commit) committer.delete(page.path) committer.add_to_index(target_dir, target_name, page.format, page.raw_data) committer.after_commit do |index, _sha| @access.refresh index.update_working_dir(source_dir, source_name, page.format) index.update_working_dir(target_dir, target_name, page.format) end multi_commit ? committer : committer.commit end # Public: Update an existing page with new content. The location of the # page inside the repository will not change. If the given format is # different than the current format of the page, the filename will be # changed to reflect the new format. # # page - The Gollum::Page to update. # name - The String extension-less name of the page. # 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. # :parent - Optional Gollum::Git::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, 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 == '.' filename = (rename = page.name != name) ? Gollum::Page.cname(name) : page.filename_stripped multi_commit = !!commit[:committer] committer = multi_commit ? commit[:committer] : Committer.new(self, commit) if !rename && page.format == format committer.add(page.path, normalize(data)) else committer.delete(page.path) committer.add_to_index(dir, filename, format, data) end committer.after_commit do |index, _sha| @access.refresh index.update_working_dir(dir, page.filename_stripped, page.format) index.update_working_dir(dir, filename, 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. # :parent - Optional Gollum::Git::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, or the # Gollum::Committer instance if this is part of a batch update. def delete_page(page, commit) multi_commit = !!commit[:committer] committer = multi_commit ? commit[:committer] : Committer.new(self, commit) 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.filename_stripped, page.format) end multi_commit ? committer : committer.commit end # Public: Delete a file. # # path - The path to the file to delete # commit - The commit Hash details: # :message - The String commit message. # :name - The String author full name. # :email - The String email address. # :parent - Optional Gollum::Git::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, or the # Gollum::Committer instance if this is part of a batch update. def delete_file(path, commit) dir = ::File.dirname(path) ext = ::File.extname(path) format = ext.split('.').last || 'txt' filename = ::File.basename(path, ext) multi_commit = !!commit[:committer] committer = multi_commit ? commit[:committer] : Committer.new(self, commit) committer.delete(path) committer.after_commit do |index, _sha| dir = '' if dir == '.' @access.refresh index.update_working_dir(dir, filename, format) end multi_commit ? committer : committer.commit end # Public: Applies a reverse diff for a given page. If only 1 SHA is given, # the reverse diff will be taken from its parent (^SHA...SHA). If two SHAs # are given, the reverse diff is taken from SHA1...SHA2. # # page - The Gollum::Page to delete. # sha1 - String SHA1 of the earlier parent if two SHAs are given, # or the child. # sha2 - Optional String SHA1 of the child. # commit - The commit Hash details: # :message - The String commit message. # :name - The String author full name. # :email - The String email address. # :parent - Optional Gollum::Git::Commit parent to this update. # # Returns a String SHA1 of the new commit, or nil if the reverse diff does # not apply. def revert_page(page, sha1, sha2 = nil, commit = {}) if sha2.is_a?(Hash) commit = sha2 sha2 = nil end 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 files = [] if page files << [page.path, page.filename_stripped, page.format] else # Grit::Diff can't parse reverse diffs.... yet patch.each_line do |line| if line =~ %r(^diff --git b/.+? a/(.+)$) path = Regexp.last_match[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 committer.commit end # Public: Applies a reverse diff to the repo. If only 1 SHA is given, # the reverse diff will be taken from its parent (^SHA...SHA). If two SHAs # are given, the reverse diff is taken from SHA1...SHA2. # # sha1 - String SHA1 of the earlier parent if two SHAs are given, # or the child. # sha2 - Optional String SHA1 of the child. # commit - The commit Hash details: # :message - The String commit message. # :name - The String author full name. # :email - The String email address. # # Returns a String SHA1 of the new commit, or nil if the reverse diff does # not apply. def revert_commit(sha1, sha2 = nil, commit = {}) revert_page(nil, sha1, sha2, commit) end # Public: Lists all pages for this wiki. # # treeish - The String commit ID or ref to find (default: @ref) # # Returns an Array of Gollum::Page instances. def pages(treeish = nil) tree_list(treeish || @ref) end # Public: Lists all non-page files for this wiki. # # treeish - The String commit ID or ref to find (default: @ref) # # Returns an Array of Gollum::File instances. def files(treeish = nil) file_list(treeish || @ref) end # Public: Returns the number of pages accessible from a commit # # ref - A String ref that is either a commit SHA or references one. # # Returns a Fixnum def size(ref = nil) tree_map_for(ref || @ref).inject(0) do |num, entry| num + (@page_class.valid_page_name?(entry.name) ? 1 : 0) end rescue Gollum::Git::NoSuchShaFound 0 end # Public: Search all pages for this wiki. # # query - The string to search for # # Returns an Array with Objects of page name and count of matches def search(query) options = {:path => page_file_dir, :ref => ref} results = {} @repo.git.grep(query, options).each do |hit| name = hit[:name] count = hit[:count] # Remove ext only from known extensions. # test.pdf => test.pdf, test.md => test file_name = Page::valid_page_name?(name) ? name.chomp(::File.extname(name)) : name results[file_name] = count.to_i end # Use git ls-files '*query*' to search for file names. Grep only searches file content. # Spaces are converted to dashes when saving pages to disk. @repo.git.ls_files(query.gsub(' ','-'), options).each do |path| # Remove ext only from known extensions. file_name = Page::valid_page_name?(path) ? path.chomp(::File.extname(path)) : path # If there's not already a result for file_name then # the value is nil and nil.to_i is 0. results[file_name] = results[file_name].to_i + 1; end results.map do |key, val| { :count => val, :name => key } end end # Public: All of the versions that have touched the Page. # # options - The options Hash: # :page - The Integer page number (default: 1). # :per_page - The Integer max count of items to return. # # Returns an Array of Gollum::Git::Commit. def log(options = {}) @repo.log(@ref, nil, log_pagination_options(options)) end # Returns the latest changes in the wiki (globally) # # options - The options Hash: # :max_count - The Integer number of items to return. # # Returns an Array of Gollum::Git::Commit. def latest_changes(options={}) options[:max_count] = 10 unless options[:max_count] @repo.log(@ref, nil, 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 # Public: Add an additional link to the filter chain. # # name - A symbol which represents the name of a class under the # Gollum::Render namespace to insert into the chain. # # loc - A "location specifier" -- that is, where to put the new # filter in the chain. This can be one of `:first`, `:last`, # `:before => :SomeElement`, or `:after => :SomeElement`, where # `:SomeElement` (if specified) is a symbol already in the # filter chain. A `:before` or `:after` which references a # filter that doesn't exist will cause `ArgumentError` to be # raised. # # Returns nothing. def add_filter(name, loc) unless name.is_a? Symbol raise ArgumentError, "Invalid filter name #{name.inspect} (must be a symbol)" end case loc when :first @filter_chain.unshift(name) when :last @filter_chain.push(name) when Hash if loc.length != 1 raise ArgumentError, "Invalid location specifier" end if ([:before, :after] && loc.keys).empty? raise ArgumentError, "Invalid location specifier" end next_to = loc.values.first relative = loc.keys.first i = @filter_chain.index(next_to) if i.nil? raise ArgumentError, "Unknown filter #{next_to.inspect}" end i += 1 if relative == :after @filter_chain.insert(i, name) else raise ArgumentError, "Invalid location specifier" end end # Remove the named filter from the filter chain. # # Returns nothing. Raises `ArgumentError` if the named filter doesn't # exist in the chain. def remove_filter(name) unless name.is_a? Symbol raise ArgumentError, "Invalid filter name #{name.inspect} (must be a symbol)" end unless @filter_chain.delete(name) raise ArgumentError, "#{name.inspect} not found in filter chain" end end ######################################################################### # # Internal Methods # ######################################################################### # The Gollum::Git::Repo associated with the wiki. # # Returns the Gollum::Git::Repo. attr_reader :repo # The String path to the Git repository that holds the Gollum site. # # Returns the String path. attr_reader :path # 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_classes # Toggles display of universal table of contents attr_reader :universal_toc # Toggles mathjax. attr_reader :mathjax # Toggles user icons. Default: 'none' attr_reader :user_icons # Toggles showing all files in files view. Default is false. # When false, only valid pages in the git repo are displayed. attr_reader :show_all # Start with collapsed file view. Default: false attr_reader :collapse_tree # Toggles file upload functionality. attr_reader :allow_uploads # Toggles whether uploaded files go into 'uploads', or a directory # named after the page they were uploaded to. attr_reader :per_page_uploads # Normalize the data. # # data - The String data to be normalized. # # Returns the normalized data String. def normalize(data) data.gsub(/\r/, '') end # Assemble a Page's filename from its name and format. # # name - The String name of the page (should be pre-canonicalized). # format - The Symbol format of the page. # # Returns the String filename. def page_file_name(name, format) name + '.' + @page_class.format_to_ext(format) end # Fill an array with a list of pages. # # ref - A String ref that is either a commit SHA or references one. # # Returns a flat Array of Gollum::Page instances. def tree_list(ref) if (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) list << entry.page(self, commit) end else [] end end # Fill an array with a list of files. # # ref - A String ref that is either a commit SHA or references one. # # Returns a flat Array of Gollum::File instances. def file_list(ref) if (sha = @access.ref_to_sha(ref)) commit = @access.commit(sha) tree_map_for(sha).inject([]) do |list, entry| next list if entry.name.start_with?('_') next list if @page_class.valid_page_name?(entry.name) list << entry.file(self, commit) end else [] end end # Creates a reverse diff for the given SHAs on the given Gollum::Page. # # page - The Gollum::Page to scope the patch to, or a String Path. # sha1 - String SHA1 of the earlier parent if two SHAs are given, # or the child. # sha2 - Optional String SHA1 of the child. # # Returns a String of the reverse Diff to apply. def full_reverse_diff_for(page, sha1, sha2 = nil) sha1, sha2 = "#{sha1}^", sha1 if sha2.nil? if page path = (page.respond_to?(:path) ? page.path : page.to_s) return repo.diff(sha2, sha1, path).first.diff end repo.diff(sha2, sha1).map { |d| d.diff }.join("\n") end # Creates a reverse diff for the given SHAs. # # sha1 - String SHA1 of the earlier parent if two SHAs are given, # or the child. # sha2 - Optional String SHA1 of the child. # # Returns a String of the reverse Diff to apply. def full_reverse_diff(sha1, sha2 = nil) full_reverse_diff_for(nil, sha1, sha2) end # Gets the default name for commits. # # Returns the String name. def default_committer_name @default_committer_name ||= \ @repo.config['user.name'] || self.class.default_committer_name end # Gets the default email for commits. # # Returns the String email address. def default_committer_email email = @repo.config['user.email'] email = email.delete('<>') if email @default_committer_email ||= email || self.class.default_committer_email end # Gets the commit object for the given ref or sha. # # ref - A string ref or SHA pointing to a valid commit. # # Returns a Gollum::Git::Commit instance. def commit_for(ref) @access.commit(ref) rescue Gollum::Git::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. # # ref - A String ref that is either a commit SHA or references one. # ignore_page_file_dir - Boolean, if true, searches all files within the git repo, regardless of dir/subdir # # Returns an Array of BlobEntry instances. def tree_map_for(ref, ignore_page_file_dir=false) if ignore_page_file_dir && !@page_file_dir.nil? @root_access ||= GitAccess.new(path, nil, @repo_is_bare) @root_access.tree(ref) else @access.tree(ref) end rescue Gollum::Git::NoSuchShaFound [] end def inspect %(#<#{self.class.name}:#{object_id} #{@repo.path}>) end end end gollum-lib-4.2.7/lib/gollum-lib/markup.rb0000644000004100000410000001323113172672532020264 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ require 'digest/sha1' require 'cgi' require 'rouge' require 'base64' require File.expand_path '../helpers', __FILE__ # Use pygments if it's installed begin require 'pygments' Pygments.start rescue Exception end module Gollum class Markup include Helpers @formats = {} class << self # Only use the formats that are specified in config.rb def formats if defined? Gollum::Page::FORMAT_NAMES @formats.select { |_, value| Gollum::Page::FORMAT_NAMES.values.include? value[:name] } else @formats end end # Register a file extension and associated markup type # # ext - The file extension # name - The name of the markup type # options - Hash of options: # regexp - Regexp to match against. # Defaults to exact match of ext. # # If given a block, that block will be registered with GitHub::Markup to # render any matching pages def register(ext, name, options = {}, &block) @formats[ext] = { :name => name, :regexp => options.fetch(:regexp, Regexp.new(ext.to_s)), :reverse_links => options.fetch(:reverse_links, false) } end end attr_accessor :toc attr_accessor :metadata attr_reader :encoding attr_reader :sanitize attr_reader :format attr_reader :wiki attr_reader :page attr_reader :parent_page attr_reader :sub_page attr_reader :name attr_reader :include_levels attr_reader :to_xml_opts attr_reader :dir # Initialize a new Markup object. # # page - The Gollum::Page. # # Returns a new Gollum::Markup object, ready for rendering. def initialize(page) if page @wiki = page.wiki @name = page.filename @data = page.text_data @version = page.version.id if page.version @format = page.format @sub_page = page.sub_page @parent_page = page.parent_page @page = page @dir = ::File.dirname(page.path) end @metadata = nil @to_xml_opts = { :save_with => Nokogiri::XML::Node::SaveOptions::DEFAULT_XHTML ^ 1, :indent => 0, :encoding => 'UTF-8' } end def reverse_links? self.class.formats[@format][:reverse_links] end # Render data using default chain in the target format. # # data - the data to render # format - format to use as a symbol # name - name using the extension of the format # # Returns the processed data def render_default(data, format=:markdown, name='render_default.md') # set instance vars so we're able to render data without a wiki or page. @format = format @name = name chain = [:Metadata, :PlainText, :Emoji, :TOC, :RemoteCode, :Code, :Sanitize, :WSD, :Tags, :Render] filter_chain = chain.map do |r| Gollum::Filter.const_get(r).new(self) end process_chain data, filter_chain end # Process the filter chain # # data - the data to send through the chain # filter_chain - the chain to process # # Returns the formatted data def process_chain(data, filter_chain) # First we extract the data through the chain... filter_chain.each do |filter| data = filter.extract(data) end # Then we process the data through the chain *backwards* filter_chain.reverse.each do |filter| data = filter.process(data) end # Finally, a little bit of cleanup, just because data.gsub!(/

    <\/p>/) do '' end data end # Render the content with Gollum wiki syntax on top of the file's own # markup language. # # no_follow - Boolean that determines if rel="nofollow" is added to all # tags. # encoding - Encoding Constant or String. # # Returns the formatted String content. def render(no_follow = false, encoding = nil, include_levels = 10) @sanitize = no_follow ? @wiki.history_sanitizer : @wiki.sanitizer @encoding = encoding @include_levels = include_levels data = @data.dup filter_chain = @wiki.filter_chain.map do |r| Gollum::Filter.const_get(r).new(self) end # Since the last 'extract' action in our chain *should* be the markup # to HTML converter, we now have HTML which we can parse and yield, for # anyone who wants it if block_given? yield Nokogiri::HTML::DocumentFragment.parse(data) end process_chain data, filter_chain end # Find the given file in the repo. # # name - The String absolute or relative path of the file. # # Returns the Gollum::File or nil if none was found. def find_file(name, version=@version) if name =~ /^\// @wiki.file(name[1..-1], version) else path = @dir == '.' ? name : ::File.join(@dir, name) @wiki.file(path, version) end 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 MarkupGFM = Markup end gollum-lib-4.2.7/lib/gollum-lib/page.rb0000644000004100000410000003517213172672532017711 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ module Gollum class Page include Pagination Wiki.page_class = self SUBPAGENAMES = [:header, :footer, :sidebar] # Sets a Boolean determing whether this page is a historical version. # # Returns nothing. attr_writer :historical # Parent page if this is a sub page # # Returns a Page attr_accessor :parent_page # Checks a filename against the registered markup extensions # # filename - String filename, like "Home.md" # # Returns e.g. ["Home", :markdown], or [] if the extension is unregistered def self.parse_filename(filename) return [] unless filename =~ /^(.+)\.([a-zA-Z]\w*)$/i pref, ext = Regexp.last_match[1], Regexp.last_match[2] Gollum::Markup.formats.each_pair do |name, format| return [pref, name] if ext =~ format[:regexp] end [] end # Checks if a filename has a valid, registered extension # # filename - String filename, like "Home.md". # # Returns the matching String basename of the file without the extension. def self.valid_filename?(filename) self.parse_filename(filename).first end # Checks if a filename has a valid extension understood by GitHub::Markup. # Also, checks if the filename has no "_" in the front (such as # _Footer.md). # # filename - String filename, like "Home.md". # # Returns the matching String basename of the file without the extension. def self.valid_page_name?(filename) match = valid_filename?(filename) filename =~ /^_/ ? false : match end # Public: The format of a given filename. # # filename - The String filename. # # Returns the Symbol format of the page; one of the registered format types def self.format_for(filename) self.parse_filename(filename).last end # Reusable filter to turn a filename (without path) into a canonical name. # Strips extension, converts dashes to spaces. # # Returns the filtered String. def self.canonicalize_filename(filename) strip_filename(filename).gsub('-', ' ') end # Reusable filter to strip extension and path from filename # # filename - The string path or filename to strip # # Returns the stripped String. def self.strip_filename(filename) ::File.basename(filename, ::File.extname(filename)) end # Public: Initialize a page. # # wiki - The Gollum::Wiki in question. # # Returns a newly initialized Gollum::Page. def initialize(wiki) @wiki = wiki @blob = nil @formatted_data = nil @doc = nil @parent_page = nil end # Public: The on-disk filename of the page including extension. # # Returns the String name. def filename @blob && @blob.name end # Public: The on-disk filename of the page with extension stripped. # # Returns the String name. def filename_stripped self.class.strip_filename(filename) end # Public: The canonical page name without extension, and dashes converted # to spaces. # # Returns the String name. def name self.class.canonicalize_filename(filename) end # Public: The title will be constructed from the # filename by stripping the extension and replacing any dashes with # spaces. # # Returns the fully sanitized String title. def title Sanitize.clean(name).strip end # Public: Determines if this is a sub-page # Sub-pages have filenames beginning with an underscore # # Returns true or false. def sub_page filename =~ /^_/ end # Public: The path of the page within the repo. # # Returns the String path. attr_reader :path # Public: The url path required to reach this page within the repo. # # Returns the String url_path def url_path path = if self.path.include?('/') self.path.sub(/\/[^\/]+$/, '/') else '' end path << Page.cname(self.name, '-', '-') path end # Public: The display form of the url path required to reach this page within the repo. # # Returns the String url_path def url_path_display url_path.gsub("-", " ") end # Public: Defines title for page.rb # # Returns the String title def url_path_title metadata_title || url_path_display end # Public: Metadata title # # Set with in page content # # Returns the String title or nil if not defined def metadata_title if metadata title = metadata['title'] return title unless title.nil? end nil end # Public: The url_path, but CGI escaped. # # Returns the String url_path def escaped_url_path CGI.escape(self.url_path).gsub('%2F', '/') end # Public: The raw contents of the page. # # Returns the String data. def raw_data return nil unless @blob if !@wiki.repo.bare && @blob.is_symlink new_path = @blob.symlink_target(::File.join(@wiki.repo.path, '..', self.path)) return IO.read(new_path) if new_path end @blob.data end # Public: A text data encoded in specified encoding. # # encoding - An Encoding or nil # # Returns a character encoding aware String. def text_data(encoding=nil) if raw_data.respond_to?(:encoding) raw_data.force_encoding(encoding || Encoding::UTF_8) else raw_data end end # Public: The formatted contents of the page. # # encoding - Encoding Constant or String. # # Returns the String data. def formatted_data(encoding = nil, include_levels = 10, &block) return nil unless @blob if @formatted_data && @doc then yield @doc if block_given? else @formatted_data = markup_class.render(historical?, encoding, include_levels) do |doc| @doc = doc yield doc if block_given? end end @formatted_data end # Public: The table of contents of the page. # # formatted_data - page already marked up in html. # # Returns the String data. def toc_data return @parent_page.toc_data if @parent_page and @sub_page formatted_data if markup_class.toc == nil markup_class.toc end # Public: Embedded metadata. # # Returns Hash of metadata. def metadata formatted_data if markup_class.metadata == nil markup_class.metadata end # Public: The format of the page. # # Returns the Symbol format of the page; one of the registered format types def format self.class.format_for(@blob.name) end # Gets the Gollum::Markup instance that will render this page's content. # # Returns a Gollum::Markup instance. def markup_class @markup_class ||= @wiki.markup_classes[format].new(self) end # Public: The current version of the page. # # Returns the Gollum::Git::Commit. attr_reader :version # Public: All of the versions that have touched the Page. # # options - The options Hash: # :page - The Integer page number (default: 1). # :per_page - The Integer max count of items to return. # :follow - Follow's a file across renames, slower. (default: false) # # Returns an Array of Gollum::Git::Commit. def versions(options = {}) @wiki.repo.git.versions_for_path(@path, @wiki.ref, log_pagination_options(options)) end # Public: The last version that has touched the Page. Can be nil. # # Returns Gollum::Git::Commit, or nil. def last_version return @last_version if defined? @last_version @last_version = @wiki.repo.git.versions_for_path(@path, @wiki.ref, {:max_count => 1}).first end # Public: The first 7 characters of the current version. # # Returns the first 7 characters of the current version. def version_short version.to_s[0, 7] end # Public: The header Page. # # Returns the header Page or nil if none exists. def header find_sub_pages unless defined?(@header) @header end # Public: The footer Page. # # Returns the footer Page or nil if none exists. def footer find_sub_pages unless defined?(@footer) @footer end # Public: The sidebar Page. # # Returns the sidebar Page or nil if none exists. def sidebar find_sub_pages unless defined?(@sidebar) @sidebar end # Gets a Boolean determining whether this page is a historical version. # Historical pages are pulled using exact SHA hashes and format all links # with rel="nofollow" # # Returns true if the page is pulled from a named branch or tag, or false. def historical? !!@historical end ######################################################################### # # Class Methods # ######################################################################### # Convert a human page name into a canonical page name. # # name - The String human page name. # char_white_sub - Substitution for whitespace # char_other_sub - Substitution for other special chars # # Examples # # Page.cname("Bilbo Baggins") # # => 'Bilbo-Baggins' # # Page.cname("Bilbo Baggins",'_') # # => 'Bilbo_Baggins' # # Returns the String canonical name. def self.cname(name, char_white_sub = '-', char_other_sub = '-') name.respond_to?(:gsub) ? name.gsub(%r(\s), char_white_sub).gsub(%r([<>+]), char_other_sub) : '' end # Convert a format Symbol into an extension String. # # format - The format Symbol. # # Returns the String extension (no leading period). def self.format_to_ext(format) format == :markdown ? "md" : format.to_s end ######################################################################### # # Internal Methods # ######################################################################### # The underlying wiki repo. # # Returns the Gollum::Wiki containing the page. attr_reader :wiki # Set the Gollum::Git::Commit version of the page. # # Returns nothing. attr_writer :version # Find a page in the given Gollum repo. # # name - The human or canonical String page name to find. # version - The String version ID to find. # # Returns a Gollum::Page or nil if the page could not be found. def find(name, version, dir = nil, exact = false) map = @wiki.tree_map_for(version.to_s) if (page = find_page_in_tree(map, name, dir, exact)) page.version = version.is_a?(Gollum::Git::Commit) ? version : @wiki.commit_for(version) page.historical = page.version.to_s == version.to_s page end rescue Gollum::Git::NoSuchShaFound end # Find a page in a given tree. # # map - The Array tree map from Wiki#tree_map. # name - The canonical String page name. # checked_dir - Optional String of the directory a matching page needs # to be in. The string should # # Returns a Gollum::Page or nil if the page could not be found. def find_page_in_tree(map, name, checked_dir = nil, exact = false) return nil if !map || name.to_s.empty? checked_dir = BlobEntry.normalize_dir(checked_dir) checked_dir = '' if exact && checked_dir.nil? name = ::File.join(checked_dir, name) if checked_dir map.each do |entry| next if entry.name.to_s.empty? path = checked_dir ? ::File.join(entry.dir, entry.name) : entry.name next unless page_match(name, path) return entry.page(@wiki, @version) end return nil # nothing was found end # Populate the Page with information from the Blob. # # blob - The Gollum::Git::Blob that contains the info. # path - The String directory path of the page file. # # Returns the populated Gollum::Page. def populate(blob, path=nil) @blob = blob @path = "#{path}/#{blob.name}"[1..-1] self end # The full directory path for the given tree. # # treemap - The Hash treemap containing parentage information. # tree - The Gollum::Git::Tree for which to compute the path. # # Returns the String path. def tree_path(treemap, tree) if (ptree = treemap[tree]) tree_path(treemap, ptree) + '/' + tree.name else '' end end # Compare the canonicalized versions of the two names. # # name - The human or canonical String page name. # path - the String path on disk (including file extension). # # Returns a Boolean. def page_match(name, path) if (match = self.class.valid_filename?(path)) @wiki.ws_subs.each do |sub| return true if Page.cname(name).downcase == Page.cname(match, sub).downcase end end false end # Loads sub pages. Sub page names (footers, headers, sidebars) are prefixed with # an underscore to distinguish them from other Pages. If there is not one within # the current directory, starts walking up the directory tree to try and find one # within parent directories. def find_sub_pages(subpagenames = SUBPAGENAMES, map = nil) subpagenames.each{|subpagename| instance_variable_set("@#{subpagename}", nil)} return nil if self.filename =~ /^_/ || ! self.version map ||= @wiki.tree_map_for(@wiki.ref, true) valid_names = subpagenames.map(&:capitalize).join("|") # From Ruby 2.2 onwards map.select! could be used map = map.select{|entry| entry.name =~ /^_(#{valid_names})/ } return if map.empty? subpagenames.each do |subpagename| dir = ::Pathname.new(self.path) while dir = dir.parent do subpageblob = map.find do |blob_entry| filename = "_#{subpagename.to_s.capitalize}" searchpath = dir == Pathname.new('.') ? Pathname.new(filename) : dir + filename entrypath = ::Pathname.new(blob_entry.path) # Ignore extentions entrypath = entrypath.dirname + entrypath.basename(entrypath.extname) entrypath == searchpath end if subpageblob instance_variable_set("@#{subpagename}", subpageblob.page(@wiki, @version) ) break end break if dir == Pathname.new('.') end end end def inspect %(#<#{self.class.name}:#{object_id} #{name} (#{format}) @wiki=#{@wiki.repo.path.inspect}>) end end end gollum-lib-4.2.7/lib/gollum-lib/committer.rb0000644000004100000410000002012513172672532020770 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ 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 Gollum::Git::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 = [] after_commit { |*args| Hook.execute(:post_commit, *args) } end # Public: References the Git index for this commit. # # Returns a Gollum::Git::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 Gollum::Git::Actor. def actor @actor ||= begin @options[:name] = @wiki.default_committer_name if @options[:name].nil? @options[:email] = @wiki.default_committer_email if @options[:email].nil? Gollum::Git::Actor.new(@options[:name], @options[:email]) end end # Public: The parent commits to this pending commit. # # Returns an array of Gollum::Git::Commit instances. def parents @parents ||= begin arr = [@options[:parent] || @wiki.repo.commit(@wiki.ref)] 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 filename_stripped. # 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) # spaces must be dashes dir.gsub!(' ', '-') name.gsub!(' ', '-') path = @wiki.page_file_name(name, format) dir = '/' if dir.strip.empty? fullpath = ::File.join(*[dir, path]) fullpath = fullpath[1..-1] if fullpath =~ /^\// if index.current_tree && (tree = index.current_tree / (@wiki.page_file_dir || '/')) tree = tree / dir unless tree.nil? end if tree downpath = path.downcase.sub(/\.\w+$/, '') tree.blobs.each do |blob| next if page_path_scheduled_for_deletion?(index.tree, fullpath) existing_file = blob.name.downcase.sub(/\.\w+$/, '') existing_file_ext = ::File.extname(blob.name).sub(/^\./, '') new_file_ext = ::File.extname(path).sub(/^\./, '') if downpath == existing_file && !(allow_same_ext && new_file_ext == existing_file_ext) raise DuplicatePageError.new(dir, blob.name, path) end end end fullpath = fullpath.force_encoding('ascii-8bit') if fullpath.respond_to?(:force_encoding) begin data = @wiki.normalize(data) rescue ArgumentError => err # Swallow errors that arise from data being binary raise err unless err.message.include?('invalid byte sequence') end index.add(fullpath, 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 or the stripped filename # (should be pre-canonicalized if required). # 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 !~ /^#{@wiki.page_file_dir}/ dir = dir.size.zero? ? @wiki.page_file_dir : ::File.join(@wiki.page_file_dir, dir) end path = if dir == '' @wiki.page_file_name(name, format) else ::File.join(dir, @wiki.page_file_name(name, format)) end path = path.force_encoding('ascii-8bit') if path.respond_to?(:force_encoding) Dir.chdir(::File.join(@wiki.repo.path, '..')) do if file_path_scheduled_for_deletion?(index.tree, path) @wiki.repo.git.rm(path, :force => true) else @wiki.repo.git.checkout(path, 'HEAD') 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, nil, @wiki.ref) @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) args.map! { |item| item.respond_to?(:force_encoding) ? item.force_encoding('ascii-8bit') : item } index.send(name, *args) end end end gollum-lib-4.2.7/lib/gollum-lib/git_access.rb0000644000004100000410000001506313172672532021076 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ module Gollum # Controls all access to the Git objects from Gollum. Extend this class to # add custom caching for special cases. class GitAccess # Initializes the GitAccess instance. # # path - The String path to the Git repository that holds the # Gollum site. # page_file_dir - String the directory in which all page files reside # # Returns this instance. def initialize(path, page_file_dir = nil, bare = nil) @page_file_dir = page_file_dir @path = path @repo = Gollum::Git::Repo.new(path, { :is_bare => bare }) 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, or nil if the ref isn't found. def ref_to_sha(ref) ref = ref.to_s return if ref.empty? sha = if sha?(ref) ref else get_cache(:ref, ref) { ref_to_sha!(ref) } end.to_s sha.empty? ? nil : sha 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 Gollum::Git::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: 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 Gollum::Git::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 Gollum::Git::Commit instance. # # {"abcd123" => } # attr_reader :commit_map # 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) commit = @repo.commit(ref) commit ? commit.id : nil 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.lstree(sha, { :recursive => true }) items = [] tree.each do |entry| if entry[:type] == 'blob' items << BlobEntry.new(entry[:sha], entry[:path], entry[:size], entry[:mode].to_i(8)) end end if (dir = @page_file_dir) regex = /^#{dir}\// items.select { |i| i.path =~ regex } else items 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 Gollum::Git::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 # 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.join(' '), size.to_i, mode.to_i(8)) 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}")) } path end end end gollum-lib-4.2.7/lib/gollum-lib/macro/0000755000004100000410000000000013172672532017541 5ustar www-datawww-datagollum-lib-4.2.7/lib/gollum-lib/macro/global_toc.rb0000644000004100000410000000062413172672532022175 0ustar www-datawww-datamodule Gollum class Macro class GlobalTOC < Gollum::Macro def render(title = "Global Table of Contents") if @wiki.pages.size > 0 result = '

    ' end "
    #{title}
    #{result}
    " end end end end gollum-lib-4.2.7/lib/gollum-lib/macro/series.rb0000644000004100000410000000346513172672532021370 0ustar www-datawww-datamodule Gollum class Macro class Series < Gollum::Macro def render(series_prefix = "") raise "This page's name does not match the prefix '#{series_prefix}'" unless @page.name =~ /^#{series_prefix}/ render_links(*find_series(series_prefix)) end def render_links(previous_page, next_page) result = "Previous: #{previous_page.name}" if previous_page result = "#{result}#{result ? ' | ' : ''}Next: #{next_page.name}" if next_page wrap_result(result) end def wrap_result(result) result.nil? ? "" : "
    #{result}
    " end def find_series(series_prefix = "") dir = @wiki.pages.select {|page| ::File.dirname(page.path) == ::File.dirname(@page.path)} dir.select! {|page| page.name =~ /\A#{series_prefix}/ } unless series_prefix.empty? dir.sort_by! {|page| page.name} self_index = dir.find_index {|page| page.name == @page.name} if self_index > 0 return dir[self_index-1], dir[self_index+1] else return nil, dir[self_index+1] end end end class SeriesStart < Gollum::Macro::Series def render_links(previous_page, next_page) result = "Next: #{next_page.name}" if next_page wrap_result(result) end end class SeriesEnd < Gollum::Macro::Series def render_links(previous_page, next_page) result = "Previous: #{previous_page.name}" if previous_page wrap_result(result) end end end endgollum-lib-4.2.7/lib/gollum-lib/macro/all_pages.rb0000644000004100000410000000036213172672532022016 0ustar www-datawww-datamodule Gollum class Macro class AllPages < Gollum::Macro def render if @wiki.pages.size > 0 '
      ' + @wiki.pages.map { |p| "
    • #{p.name}
    • " }.join + '
    ' end end end end end gollum-lib-4.2.7/lib/gollum-lib/macro/navigation.rb0000644000004100000410000000133513172672532022227 0ustar www-datawww-datamodule Gollum class Macro class Navigation < Gollum::Macro def render(title = "Navigate in the TOC", toc_root_path = ::File.dirname(@page.path), full_path = false) if @wiki.pages.size > 0 list_items = @wiki.pages.map do |page| if page.url_path.start_with?(toc_root_path) path_display = full_path ? page.url_path_display : page.url_path_display.sub(toc_root_path.gsub("-", " "), "").sub(/^\//,'') "
  • #{path_display}
  • " end end result = "
      #{list_items.join}
    " end "
    #{title}
    #{result}
    " end end end end gollum-lib-4.2.7/lib/gollum-lib/gitcode.rb0000644000004100000410000000302213172672532020400 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ require 'net/http' require 'net/https' # ruby 1.8.7 fix, remove at upgrade require 'uri' require 'open-uri' module Gollum class Gitcode def initialize(path) raise(ArgumentError, 'path is nil or empty') if path.nil? or path.empty? @uri = URI::HTTP.build({ :path => self.unchomp(path), :host => 'raw.github.com', :scheme => 'https', :port => 443 }) end def contents @contents ||= self.req @uri end def unchomp(p) return p if p.nil? p[0] == '/' ? p : ('/' + p) end def req(uri, cut = 1) return "Too many redirects or retries" if cut >= 10 http = Net::HTTP.new uri.host, uri.port http.use_ssl = true resp = http.get uri.path, { 'Accept' => 'text/plain', 'Cache-Control' => 'no-cache', 'Connection' => 'keep-alive', 'Host' => uri.host, 'User-Agent' => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0' } code = resp.code.to_i return resp.body if code == 200 return "Not Found" if code == 404 return "Unhandled Response Code #{code}" unless code == 304 or not resp.header['location'].nil? loc = URI.parse resp.header['location'] uri2 = loc.relative?() ? (uri + loc) : loc # overloads (+) return req uri2, (cut + 1) end end end gollum-lib-4.2.7/lib/gollum-lib/markups.rb0000644000004100000410000000135713172672532020455 0ustar www-datawww-data# ~*~ encoding: utf-8 ~*~ module Gollum class Markup GitHub::Markup::Markdown::MARKDOWN_GEMS['kramdown'] = proc { |content| Kramdown::Document.new(content, :auto_ids => false, :input => "markdown").to_html } register(:markdown, "Markdown", :regexp => /md|mkdn?|mdown|markdown/) register(:textile, "Textile") register(:rdoc, "RDoc") register(:org, "Org-mode") register(:creole, "Creole", :reverse_links => true) register(:rest, "reStructuredText", :regexp => /re?st(\.txt)?/) register(:asciidoc, "AsciiDoc") register(:mediawiki, "MediaWiki", :regexp => /(media)?wiki/, :reverse_links => true) register(:pod, "Pod") register(:txt, "Plain Text") end endgollum-lib-4.2.7/docs/0000755000004100000410000000000013172672532014557 5ustar www-datawww-datagollum-lib-4.2.7/docs/sanitization.md0000644000004100000410000000242213172672532017615 0ustar www-datawww-dataSanitization Rules ================== Gollum uses the [Sanitize](http://wonko.com/post/sanitize) gem for HTML sanitization. See `lib/gollum-lib/sanitization.rb` for actual settings. ## ALLOWED TAGS a, abbr, acronym, address, area, b, big, blockquote, br, button, caption, center, cite, code, col, colgroup, dd, del, dfn, dir, div, dl, dt, em, fieldset, font, form, h1, h2, h3, h4, h5, h6, hr, i, img, input, ins, kbd, label, legend, li, map, menu, ol, optgroup, option, p, pre, q, s, samp, select, small, span, strike, strong, sub, sup, table, tbody, td, textarea, tfoot, th, thead, tr, tt, u, ul, var ## ALLOWED ATTRIBUTES abbr, accept, accept-charset, accesskey, action, align, alt, axis, border, cellpadding, cellspacing, char, charoff, charset, checked, cite, class, clear, cols, colspan, color, compact, coords, datetime, dir, disabled, enctype, for, frame, headers, height, href, hreflang, hspace, id, ismap, label, lang, longdesc, maxlength, media, method, multiple, name, nohref, noshade, nowrap, prompt, readonly, rel, rev, rows, rowspan, rules, scope, selected, shape, size, span, src, start, summary, tabindex, target, title, type, usemap, valign, value, vspace, width ## ALLOWED PROTOCOLS a href: http, https, mailto, ftp, irc, apt img src: http, https form action: http, https gollum-lib-4.2.7/licenses/0000755000004100000410000000000013172672532015434 5ustar www-datawww-datagollum-lib-4.2.7/licenses/licenses.txt0000644000004100000410000000062313172672532020003 0ustar www-datawww-dataFor gollum code, everything should fall under the existing MIT License. Alternative permissive licenses (such as BSD) for 3rd party dependencies are acceptable. For image assets in Gollum, CC BY or CC BY-SA is fine. Anything released under a copyleft license (for example GPL, AGPL, LGPL, MPL, EPL, etc.) is not permitted in gollum. Public domain, CC BY or CC BY-SA for code in gollum is not permitted. gollum-lib-4.2.7/LICENSE0000644000004100000410000000210013172672532014625 0ustar www-datawww-data(The MIT License) Copyright (c) Tom Preston-Werner, Rick Olson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. gollum-lib-4.2.7/gemspec.rb0000644000004100000410000000760713172672532015611 0ustar www-datawww-datadef specification(version, default_adapter, platform = nil) Proc.new do |s| s.specification_version = 2 if s.respond_to? :specification_version= s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version= s.rubygems_version = '0.0.1' s.required_ruby_version = '>= 1.9' s.name = 'gollum-lib' s.version = version s.platform = platform if platform s.date = '2017-07-31' s.rubyforge_project = 'gollum-lib' s.license = 'MIT' s.summary = 'A simple, Git-powered wiki.' s.description = 'A simple, Git-powered wiki with a sweet API and local frontend.' s.authors = ['Tom Preston-Werner', 'Rick Olson'] s.email = 'tom@github.com' s.homepage = 'http://github.com/gollum/gollum-lib' s.require_paths = %w(lib) s.rdoc_options = ['--charset=UTF-8'] s.extra_rdoc_files = %w(README.md LICENSE) s.add_dependency *default_adapter s.add_dependency 'rouge', '~> 2.1' if RUBY_VERSION < '2.1' s.add_dependency 'nokogiri', '~> 1.6.1' else s.add_dependency 'nokogiri', '>= 1.6.1', '< 2.0' end s.add_dependency 'stringex', '~> 2.6' s.add_dependency 'sanitize', '~> 2.1' s.add_dependency 'github-markup', '~> 1.6' s.add_dependency 'gemojione', '~> 3.2' s.add_development_dependency 'org-ruby', '~> 0.9.9' s.add_development_dependency 'kramdown', '~> 1.6.0' s.add_development_dependency 'RedCloth', '~> 4.2.9' s.add_development_dependency 'mocha', '~> 1.1.0' s.add_development_dependency 'shoulda', '~> 3.5.0' s.add_development_dependency 'wikicloth', '~> 0.8.3' s.add_development_dependency 'rake', '~> 10.4.0' s.add_development_dependency 'pry', '~> 0.10.1' # required by pry s.add_development_dependency 'rb-readline', '~> 0.5.1' # updating minitest-reporters requires a new minitest which fails with gollum's tests. s.add_development_dependency 'test-unit', '~> 3.1.5' s.add_development_dependency 'minitest-reporters', '~> 0.14.16' s.add_development_dependency 'nokogiri-diff', '~> 0.2.0' # required by guard s.add_development_dependency 'guard', '~> 2.8.2' s.add_development_dependency 'guard-minitest', '~> 2.3.2' s.add_development_dependency 'rb-inotify', '~> 0.9.3' s.add_development_dependency 'rb-fsevent', '~> 0.9.4' s.add_development_dependency 'rb-fchange', '~> 0.0.6' s.add_development_dependency 'twitter_cldr', '~> 3.1.0' # = MANIFEST = s.files = %w( Gemfile HISTORY.md LICENSE README.md Rakefile docs/sanitization.md gemspec.rb gollum-lib.gemspec gollum-lib_java.gemspec lib/gollum-lib.rb lib/gollum-lib/blob_entry.rb lib/gollum-lib/committer.rb lib/gollum-lib/file.rb lib/gollum-lib/file_view.rb lib/gollum-lib/filter.rb lib/gollum-lib/filter/code.rb lib/gollum-lib/filter/emoji.rb lib/gollum-lib/filter/macro.rb lib/gollum-lib/filter/metadata.rb lib/gollum-lib/filter/plain_text.rb lib/gollum-lib/filter/plantuml.rb lib/gollum-lib/filter/remote_code.rb lib/gollum-lib/filter/render.rb lib/gollum-lib/filter/sanitize.rb lib/gollum-lib/filter/tags.rb lib/gollum-lib/filter/toc.rb lib/gollum-lib/filter/wsd.rb lib/gollum-lib/git_access.rb lib/gollum-lib/gitcode.rb lib/gollum-lib/helpers.rb lib/gollum-lib/hook.rb lib/gollum-lib/macro.rb lib/gollum-lib/macro/all_pages.rb lib/gollum-lib/macro/global_toc.rb lib/gollum-lib/macro/navigation.rb lib/gollum-lib/macro/series.rb lib/gollum-lib/markup.rb lib/gollum-lib/markups.rb lib/gollum-lib/page.rb lib/gollum-lib/pagination.rb lib/gollum-lib/sanitization.rb lib/gollum-lib/version.rb lib/gollum-lib/wiki.rb licenses/licenses.txt ) # = MANIFEST = s.test_files = s.files.select { |path| path =~ /^test\/test_.*\.rb/ } end end gollum-lib-4.2.7/README.md0000644000004100000410000001665613172672532015124 0ustar www-datawww-datagollum lib -- A wiki built on top of Git ======================================== [![Gem Version](https://badge.fury.io/rb/gollum-lib.svg)](http://badge.fury.io/rb/gollum-lib) [![Build Status](https://travis-ci.org/gollum/gollum-lib.svg?branch=master)](https://travis-ci.org/gollum/gollum-lib) [![Dependency Status](https://gemnasium.com/gollum/gollum-lib.svg)](https://gemnasium.com/gollum/gollum-lib) ## DESCRIPTION [Gollum](https://github.com/gollum/gollum) is a simple wiki system built on top of Git that powers GitHub Wikis. Gollum-lib is the Ruby API that allows you to retrieve raw or formatted wiki content from a Git repository, write new content to the repository, and collect various meta data about the wiki as a whole. Gollum-lib follows the rules of [Semantic Versioning](http://semver.org/) and uses [TomDoc](http://tomdoc.org/) for inline documentation. ## SYSTEM REQUIREMENTS - Ruby 1.9.3+ (>2.0 recommended) - Unix like operating system (OS X, Ubuntu, Debian, and more) - Will not work on Windows with the default [grit](https://github.com/github/grit) adapter, but might work via JRuby (please let us know!) ## INSTALLATION The best way to install Gollum-lib is with RubyGems: ```bash $ [sudo] gem install gollum-lib ``` If you're installing from source, you can use [Bundler][bundler] to pick up all the gems: ```bash $ bundle install ``` In order to use the various formats that Gollum supports, you will need to separately install the necessary dependencies for each format. You only need to install the dependencies for the formats that you plan to use. * [AsciiDoc](http://www.methods.co.nz/asciidoc/) -- `gem install asciidoctor` * [Creole](http://wikicreole.org/) -- `gem install creole` * [Markdown](http://daringfireball.net/projects/markdown/) -- `gem install redcarpet` * [GitHub Flavored Markdown](https://help.github.com/articles/github-flavored-markdown) -- `gem install github-markdown` * [Org](http://orgmode.org/) -- `gem install org-ruby` * [Pod](http://search.cpan.org/dist/perl/pod/perlpod.pod) -- `Pod::Simple::HTML` comes with Perl >= 5.10. Lower versions should install Pod::Simple from CPAN. * [RDoc](http://rdoc.sourceforge.net/) * [ReStructuredText](http://docutils.sourceforge.net/rst.html) -- `easy_install docutils` * [Textile](http://www.textism.com/tools/textile/) -- `gem install RedCloth` * [MediaWiki](http://www.mediawiki.org/wiki/Help:Formatting) -- `gem install wikicloth` [bundler]: http://gembundler.com/ ## SYNTAX Gollum supports a variety of formats and extensions (Markdown, MediaWiki, Textile, …). On top of these formats Gollum lets you insert headers, footers, links, image, math and more. Check out the [Gollum Wiki](https://github.com/gollum/gollum/wiki) for all of Gollum's formats and syntactic options. ## API DOCUMENTATION Initialize the `Gollum::Repo` object: ```ruby # Require rubygems if necessary require 'rubygems' # Require the Gollum library require 'gollum-lib' # Create a new Gollum::Wiki object by initializing it with the path to the # Git repository. wiki = Gollum::Wiki.new("my-gollum-repo.git") # => ``` By default, internal wiki links are all absolute from the root. To specify a different base path, you can specify the `:base_path` option: ```ruby wiki = Gollum::Wiki.new("my-gollum-repo.git", :base_path => "/wiki") ``` Note that `base_path` just modifies the links. Get the latest version of the given human or canonical page name: ```ruby page = wiki.page('page-name') # => page.raw_data # => "# My wiki page" page.formatted_data # => "

    My wiki page

    " page.format # => :markdown vsn = page.version # => vsn.id # => '3ca43e12377ea1e32ea5c9ce5992ec8bf266e3e5' ``` Get the footer (if any) for a given page: ```ruby page.footer # => ``` Get the header (if any) for a given page: ```ruby page.header # => ``` Get a list of versions for a given page: ```ruby vsns = wiki.page('page-name').versions # => [] vsns.first.id # => '3ca43e12377ea1e32ea5c9ce5992ec8bf266e3e5' vsns.first.authored_date # => Sun Mar 28 19:11:21 -0700 2010 ``` Get a specific version of a given canonical page file: ```ruby wiki.page('page-name', '5ec521178e0eec4dc39741a8978a2ba6616d0f0a') ``` Get the latest version of a given static file: ```ruby file = wiki.file('asset.js') # => file.raw_data # => "alert('hello');" file.version # => ``` Get a specific version of a given static file: ```ruby wiki.file('asset.js', '5ec521178e0eec4dc39741a8978a2ba6616d0f0a') ``` Get an in-memory Page preview (useful for generating previews for web interfaces): ```ruby preview = wiki.preview_page("My Page", "# Contents", :markdown) preview.formatted_data # => "

    Contents

    " ``` Methods that write to the repository require a Hash of commit data that takes the following form: ```ruby commit = { :message => 'commit message', :name => 'Tom Preston-Werner', :email => 'tom@github.com' } ``` Write a new version of a page (the file will be created if it does not already exist) and commit the change. The file will be written at the repo root. ```ruby wiki.write_page('Page Name', :markdown, 'Page contents', commit) ``` Update an existing page. If the format is different than the page's current format, the file name will be changed to reflect the new format. ```ruby page = wiki.page('Page Name') wiki.update_page(page, page.name, page.format, 'Page contents', commit) ``` To delete a page and commit the change: ```ruby wiki.delete_page(page, commit) ``` Register or unregister a hook to be called after a page commit: ```ruby Gollum::Hook.register(:post_commit, :hook_id) do |committer, sha1| # Your code here end Gollum::Hook.unregister(:post_commit, :hook_id) ``` ## WINDOWS FILENAME VALIDATION Note that filenames on windows must not contain any of the following characters `\ / : * ? " < > |`. See [this support article](http://support.microsoft.com/kb/177506) for details. ## CONTRIBUTE If you'd like to hack on Gollum-lib, start by forking the repo on GitHub: http://github.com/gollum/gollum-lib To get all of the dependencies, install the gem first. The best way to get your changes merged back into core is as follows: 1. Clone down your fork 1. Create a thoughtfully named topic branch to contain your change 1. Hack away 1. Add tests and make sure everything still passes by running `rake` 1. If you are adding new functionality, document it in the README 1. Do not change the version number, I will do that on my end 1. If necessary, rebase your commits into logical chunks, without errors 1. Push the branch up to GitHub 1. Send a pull request to the gollum/gollum-lib project. ## RELEASING Gollum-lib uses [Semantic Versioning](http://semver.org/). Having `x.y.z` : For z releases: ```bash $ rake bump $ rake release ``` For x.y releases: ```bash $ rake gemspec $ rake release ``` ## BUILDING THE GEM FROM MASTER ```bash $ gem uninstall -aIx gollum-lib $ git clone https://github.com/gollum/gollum-lib.git $ cd gollum-lib gollum-lib$ rake build gollum-lib$ rake install ``` ## RUN THE TESTS ```bash $ bundle install $ bundle exec rake test ``` ## WORK WITH TEST REPOS An example of how to add a test file to the bare repository `lotr.git`. ```bash $ mkdir tmp; cd tmp $ git clone ../lotr.git/ . Cloning into '.'... done. $ git log $ echo "test" > test.md $ git add . ; git commit -am "Add test" $ git push ../lotr.git/ master ```