diff --git a/bin/gollum b/bin/gollum index 11d9e91b..5ce8ce7e 100755 --- a/bin/gollum +++ b/bin/gollum @@ -19,6 +19,8 @@ require 'gollum' exec = {} options = { 'port' => 4567, 'bind' => '0.0.0.0' } +wiki_options = {} + opts = OptionParser.new do |opts| opts.banner = help @@ -42,6 +44,10 @@ opts = OptionParser.new do |opts| opts.on("--irb", "Start an irb process with gollum loaded for the current wiki.") do options['irb'] = true end + + opts.on("--page-file-dir [PATH]", "Specify the sub directory for all page files (default: repository root).") do |path| + wiki_options[:page_file_dir] = path + end end # Read command line options into `options` hash @@ -67,13 +73,13 @@ if options['irb'] ARGV.replace(args) @__initialized = true end - + ws = WorkSpace.new(binding) irb = Irb.new(ws) - + @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC] @CONF[:MAIN_CONTEXT] = irb.context - + catch(:IRB_EXIT) do irb.eval_input end @@ -81,10 +87,10 @@ if options['irb'] end begin - wiki = Gollum::Wiki.new(gollum_path) + wiki = Gollum::Wiki.new(gollum_path, wiki_options) if !wiki.exist? then raise Grit::InvalidGitRepositoryError end puts "Loaded Gollum wiki at #{File.expand_path(gollum_path).inspect}." - puts + puts puts %( page = wiki.page('page-name')) puts %( # => ) puts @@ -103,11 +109,14 @@ if options['irb'] else require 'gollum/frontend/app' Precious::App.set(:gollum_path, gollum_path) + Precious::App.set(:wiki_options, wiki_options) + if cfg = options['config'] # If the path begins with a '/' it will be considered an absolute path, # otherwise it will be relative to the CWD - cfg = File.join(Dir.getwd, cfg) unless cfg.slice(0) == File::SEPARATOR + cfg = File.join(Dir.getwd, cfg) unless cfg.slice(0) == File::SEPARATOR require cfg end + Precious::App.run!(options) end diff --git a/lib/gollum/frontend/app.rb b/lib/gollum/frontend/app.rb index 06329494..355cf826 100644 --- a/lib/gollum/frontend/app.rb +++ b/lib/gollum/frontend/app.rb @@ -44,7 +44,7 @@ module Precious get '/edit/*' do @name = params[:splat].first - wiki = Gollum::Wiki.new(settings.gollum_path) + wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) if page = wiki.page(@name) @page = page @content = page.raw_data @@ -55,7 +55,7 @@ module Precious end post '/edit/*' do - wiki = Gollum::Wiki.new(settings.gollum_path) + wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) page = wiki.page(params[:splat].first) name = params[:rename] || page.name msg = commit_message @@ -69,7 +69,7 @@ module Precious post '/create' do name = params[:page] - wiki = Gollum::Wiki.new(settings.gollum_path) + wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) format = params[:format].intern @@ -83,7 +83,7 @@ module Precious end post '/revert/:page/*' do - wiki = Gollum::Wiki.new(settings.gollum_path) + wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) @name = params[:page] @page = wiki.page(@name) shas = params[:splat].first.split("/") @@ -103,7 +103,7 @@ module Precious end post '/preview' do - wiki = Gollum::Wiki.new(settings.gollum_path) + wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) @name = "Preview" @page = wiki.preview_page(@name, params[:content], params[:format]) @content = @page.formatted_data @@ -112,7 +112,7 @@ module Precious get '/history/:name' do @name = params[:name] - wiki = Gollum::Wiki.new(settings.gollum_path) + wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) @page = wiki.page(@name) @page_num = [params[:page].to_i, 1].max @versions = @page.versions :page => @page_num @@ -134,7 +134,7 @@ module Precious get '/compare/:name/:version_list' do @name = params[:name] @versions = params[:version_list].split(/\.{2,3}/) - wiki = Gollum::Wiki.new(settings.gollum_path) + wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) @page = wiki.page(@name) diffs = wiki.repo.diff(@versions.first, @versions.last, @page.path) @diff = diffs.first @@ -147,7 +147,7 @@ module Precious get %r{/(.+?)/([0-9a-f]{40})} do name = params[:captures][0] - wiki = Gollum::Wiki.new(settings.gollum_path) + wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) if page = wiki.page(name, params[:captures][1]) @page = page @name = name @@ -160,7 +160,7 @@ module Precious get '/search' do @query = params[:q] - wiki = Gollum::Wiki.new(settings.gollum_path) + wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) @results = wiki.search @query @name = @query mustache :search @@ -171,7 +171,7 @@ module Precious end def show_page_or_file(name) - wiki = Gollum::Wiki.new(settings.gollum_path) + wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) if page = wiki.page(name) @page = page @name = name diff --git a/lib/gollum/git_access.rb b/lib/gollum/git_access.rb index 150044d3..808e4f2e 100644 --- a/lib/gollum/git_access.rb +++ b/lib/gollum/git_access.rb @@ -2,7 +2,15 @@ module Gollum # Controls all access to the Git objects from Gollum. Extend this class to # add custom caching for special cases. class GitAccess - def initialize(path) + # Initializes the GitAccess instance. + # + # path - The String path to the Git repository that holds the + # Gollum site. + # page_file_dir - String the directory in which all page files reside + # + # Returns this instance. + def initialize(path, page_file_dir = nil) + @page_file_dir = page_file_dir @path = path @repo = Grit::Repo.new(path) clear @@ -15,7 +23,7 @@ module Gollum @repo.git.exist? end - # Public: Converts a given Git reference to a SHA, using the cache if + # Public: Converts a given Git reference to a SHA, using the cache if # available. # # ref - a String Git reference (ex: "master") @@ -29,7 +37,7 @@ module Gollum end end - # Public: Gets a recursive list of Git blobs for the whole tree at the + # Public: Gets a recursive list of Git blobs for the whole tree at the # given commit. # # ref - A String Git reference or Git SHA to a commit. @@ -144,10 +152,17 @@ module Gollum # # Returns an Array of BlobEntry instances. def tree!(sha) - tree = @repo.git.native(:ls_tree, + tree = @repo.git.native(:ls_tree, {:r => true, :l => true, :z => true}, sha) - tree.split("\0").inject([]) do |items, line| - items << parse_tree_line(line) + items = tree.split("\0").inject([]) do |memo, line| + memo << parse_tree_line(line) + end + + if dir = @page_file_dir + regex = /^#{dir}\// + items.select { |i| i.path =~ regex } + else + items end end @@ -201,7 +216,7 @@ module Gollum # Parses a line of output from the `ls-tree` command. # # line - A String line of output: - # "100644 blob 839c2291b30495b9a882c17d08254d3c90d8fb53 Home.md" + # "100644 blob 839c2291b30495b9a882c17d08254d3c90d8fb53 Home.md" # # Returns an Array of BlobEntry instances. def parse_tree_line(line) diff --git a/lib/gollum/wiki.rb b/lib/gollum/wiki.rb index c94973eb..76107586 100644 --- a/lib/gollum/wiki.rb +++ b/lib/gollum/wiki.rb @@ -94,17 +94,21 @@ module Gollum # Gets the sanitization options for older page revisions used by this Wiki. attr_reader :history_sanitization + # Gets the String directory in which all page files reside. + attr_reader :page_file_dir + # Public: Initialize a new Gollum Repo. # - # repo - The String path to the Git repository that holds the Gollum + # path - The String path to the Git repository that holds the Gollum # site. # options - Optional Hash: - # :base_path - String base path for all Wiki links. - # Default: "/" - # :page_class - The page Class. Default: Gollum::Page - # :file_class - The file Class. Default: Gollum::File - # :markup_class - The markup Class. Default: Gollum::Markup - # :sanitization - An instance of Sanitization. + # :base_path - String base path for all Wiki links. + # Default: "/" + # :page_class - The page Class. Default: Gollum::Page + # :file_class - The file Class. Default: Gollum::File + # :markup_class - The markup Class. Default: Gollum::Markup + # :sanitization - An instance of Sanitization. + # :page_file_dir - String the directory in which all page files reside # # Returns a fresh Gollum::Repo. def initialize(path, options = {}) @@ -112,14 +116,15 @@ module Gollum options[:access] = path path = path.path end - @path = path - @access = options[:access] || GitAccess.new(path) - @base_path = options[:base_path] || "/" - @page_class = options[:page_class] || self.class.page_class - @file_class = options[:file_class] || self.class.file_class - @markup_class = options[:markup_class] || self.class.markup_class - @repo = @access.repo - @sanitization = options[:sanitization] || self.class.sanitization + @path = path + @page_file_dir = options[:page_file_dir] + @access = options[:access] || GitAccess.new(path, @page_file_dir) + @base_path = options[:base_path] || "/" + @page_class = options[:page_class] || self.class.page_class + @file_class = options[:file_class] || self.class.file_class + @markup_class = options[:markup_class] || self.class.markup_class + @repo = @access.repo + @sanitization = options[:sanitization] || self.class.sanitization @history_sanitization = options[:history_sanitization] || self.class.history_sanitization end @@ -361,10 +366,10 @@ module Gollum # # Returns an Array with Objects of page name and count of matches def search(query) - # See: http://github.com/Sirupsen/gollum/commit/f0a6f52bdaf6bee8253ca33bb3fceaeb27bfb87e - search_output = @repo.git.grep({:c => query}, 'master') + args = [{:c => query}, 'master', '--'] + args << '--' << @page_file_dir if @page_file_dir - search_output.split("\n").collect do |line| + @repo.git.grep(*args).split("\n").map! do |line| result = line.split(':') file_name = Gollum::Page.canonicalize_filename(::File.basename(result[1])) @@ -470,13 +475,17 @@ module Gollum # Returns nothing. def update_working_dir(index, dir, name, format) unless @repo.bare - path = - if dir == '' - page_file_name(name, format) - else - ::File.join(dir, page_file_name(name, format)) + if @page_file_dir + dir = dir.size.zero? ? @page_file_dir : File.join(dir, @page_file_dir) end + path = + if dir == '' + page_file_name(name, format) + else + ::File.join(dir, page_file_name(name, format)) + end + Dir.chdir(::File.join(@repo.path, '..')) do if file_path_scheduled_for_deletion?(index.tree, path) @repo.git.rm({'f' => true}, '--', path) @@ -571,7 +580,7 @@ module Gollum dir = '/' if dir.strip.empty? - fullpath = ::File.join(dir, path) + fullpath = ::File.join(*[@page_file_dir, dir, path].compact) fullpath = fullpath[1..-1] if fullpath =~ /^\// if index.current_tree && tree = index.current_tree / dir diff --git a/test/test_app.rb b/test/test_app.rb index f39506b5..96aa3f19 100644 --- a/test/test_app.rb +++ b/test/test_app.rb @@ -8,6 +8,7 @@ context "Frontend" do @path = cloned_testpath("examples/revert.git") @wiki = Gollum::Wiki.new(@path) Precious::App.set(:gollum_path, @path) + Precious::App.set(:wiki_options, {}) end teardown do @@ -16,7 +17,7 @@ context "Frontend" do test "edits page" do page_1 = @wiki.page('A') - post "/edit/A", :content => 'abc', + post "/edit/A", :content => 'abc', :format => page_1.format, :message => 'def' follow_redirect! assert last_response.ok? @@ -56,7 +57,7 @@ context "Frontend" do test "renames page" do page_1 = @wiki.page('B') - post "/edit/B", :content => 'abc', + post "/edit/B", :content => 'abc', :rename => "C", :format => page_1.format, :message => 'def' follow_redirect! diff --git a/test/test_wiki.rb b/test/test_wiki.rb index 0702ccc3..e8d15568 100644 --- a/test/test_wiki.rb +++ b/test/test_wiki.rb @@ -285,3 +285,45 @@ context "Wiki sync with working directory" do FileUtils.rm_r(@path) end end + +context "page_file_dir option" do + setup do + @path = testpath('examples/pfdtest') + @repo = Grit::Repo.init(@path) + @page_file_dir = 'docs' + Dir.chdir(@path) do + Dir.mkdir(@page_file_dir) + File.open("docs/foo.md", "w"){|f| f.print "Hello foo" } + @repo.add("docs/foo.md") + File.open("bar.md", "w"){|f| f.print "Hello bar" } + @repo.add("bar.md") + @repo.commit_index("Added docs/foo.md and bar.md") + end + + @wiki = Gollum::Wiki.new(@path, :page_file_dir => @page_file_dir) + end + + test "write a page in sub directory" do + @wiki.write_page("New Page", :markdown, "Hi", commit_details) + assert_equal "Hi", File.read(File.join(@path, @page_file_dir, "New-Page.md")) + assert !File.exist?(File.join(@path, "New-Page.md")) + end + + test "a file in page file dir should be found" do + assert @wiki.page("foo") + end + + test "a file out of page file dir should not be found" do + assert !@wiki.page("bar") + end + + test "search results should be restricted in page filer dir" do + results = @wiki.search("Hello") + assert_equal 1, results.size + assert_equal "foo", results[0][:name] + end + + teardown do + FileUtils.rm_r(@path) + end +end