diff --git a/HISTORY.md b/HISTORY.md index 25a3c15f..37752ff0 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -4,6 +4,7 @@ * Optimize page write/update/delete to use Grit::Index::read_tree instead of manually recreating entire index contents. * Added --irb option for the gollum command. + * Update working dir (if present) when edited via the API (#6) * Minor Enhancements * Support a `:gollum_path` Sinatra setting for `Precious::App` * Add Wiki#size to efficiently count pages without loading them. diff --git a/README.md b/README.md index ecee5c06..5100bb18 100644 --- a/README.md +++ b/README.md @@ -326,7 +326,7 @@ Initialize the Gollum::Repo object: 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 send specify the `:base_path` option: +By default, internal wiki links are all absolute from the root. To specify a different base path, you can specify the `:base_path` option: wiki = Gollum::Wiki.new("my-gollum-repo.git", :base_path => "/wiki") diff --git a/bin/gollum b/bin/gollum index 0ef6de8f..603c8dd5 100755 --- a/bin/gollum +++ b/bin/gollum @@ -15,6 +15,7 @@ HELP require 'optparse' require 'rubygems' +require 'gollum' exec = {} options = {} @@ -65,7 +66,6 @@ if options['irb'] end end - require 'gollum' begin wiki = Gollum::Wiki.new(gollum_path) if !wiki.exist? then raise Grit::InvalidGitRepositoryError end diff --git a/gollum.gemspec b/gollum.gemspec index e13e105b..cf0833e8 100644 --- a/gollum.gemspec +++ b/gollum.gemspec @@ -23,7 +23,7 @@ Gem::Specification.new do |s| s.rdoc_options = ["--charset=UTF-8"] s.extra_rdoc_files = %w[README.md LICENSE] - s.add_dependency('grit', "~> 2.2") + s.add_dependency('grit', "~> 2.3") s.add_dependency('github-markup', [">= 0.4.0", "< 1.0.0"]) s.add_dependency('albino', "~> 1.0") s.add_dependency('sinatra', "~> 1.0") @@ -31,9 +31,11 @@ Gem::Specification.new do |s| s.add_dependency('sanitize', "~> 1.1") s.add_dependency('nokogiri', "~> 1.4") - s.add_development_dependency('shoulda') + s.add_development_dependency('RedCloth') s.add_development_dependency('mocha') s.add_development_dependency('org-ruby') + s.add_development_dependency('rdiscount') + s.add_development_dependency('shoulda') # = MANIFEST = s.files = %w[ @@ -503,4 +505,4 @@ Gem::Specification.new do |s| # = MANIFEST = s.test_files = s.files.select { |path| path =~ /^test\/test_.*\.rb/ } -end \ No newline at end of file +end diff --git a/lib/gollum/frontend/app.rb b/lib/gollum/frontend/app.rb index f7c1f4c9..bdc9f1e4 100644 --- a/lib/gollum/frontend/app.rb +++ b/lib/gollum/frontend/app.rb @@ -58,7 +58,7 @@ module Precious format = params[:format].intern name = params[:rename] if params[:rename] - wiki.update_page(page, name, format, params[:content], commit_message) + wiki.update_page(page, name, format, params[:content], commit_message(wiki)) redirect "/#{Gollum::Page.cname name}" end @@ -70,7 +70,7 @@ module Precious format = params[:format].intern begin - wiki.write_page(name, format, params[:content], commit_message) + wiki.write_page(name, format, params[:content], commit_message(wiki)) redirect "/#{name}" rescue Gollum::DuplicatePageError => e @message = "Duplicate page: #{e.message}" @@ -141,6 +141,7 @@ module Precious @content = page.formatted_data mustache :page elsif file = wiki.file(name) + content_type MIME::Types.type_for(name).to_s file.raw_data else @name = name @@ -148,10 +149,10 @@ module Precious end end - def commit_message + def commit_message(wiki) { :message => params[:message], - :name => `git config --get user.name `.strip, - :email => `git config --get user.email`.strip } + :name => wiki.repo.config['user.name'], + :email => wiki.repo.config['user.email'] } end end end diff --git a/lib/gollum/wiki.rb b/lib/gollum/wiki.rb index 25d984f0..c84650cb 100644 --- a/lib/gollum/wiki.rb +++ b/lib/gollum/wiki.rb @@ -135,9 +135,12 @@ module Gollum parents = pcommit ? [pcommit] : [] actor = Grit::Actor.new(commit[:name], commit[:email]) - sha = index.commit(commit[:message], parents, actor) + sha1 = index.commit(commit[:message], parents, actor) + @ref_map.clear - sha + update_working_dir(index, '', name, format) + + sha1 end # Public: Update an existing page with new content. The location of the @@ -162,21 +165,26 @@ module Gollum format ||= page.format index = self.repo.index + dir = ::File.dirname(page.path) + dir = '' if dir == '.' + index.read_tree(pcommit.tree.id) if page.name == name && page.format == format index.add(page.path, normalize(data)) else index.delete(page.path) - dir = ::File.dirname(page.path) - dir = '' if dir == '.' add_to_index(index, dir, name, format, data, :allow_same_ext) end actor = Grit::Actor.new(commit[:name], commit[:email]) - sha = index.commit(commit[:message], [pcommit], actor) + sha1 = index.commit(commit[:message], [pcommit], actor) + @ref_map.clear - sha + update_working_dir(index, dir, page.name, page.format) + update_working_dir(index, dir, name, format) + + sha1 end # Public: Delete a page. @@ -195,10 +203,16 @@ module Gollum index.read_tree(pcommit.tree.id) index.delete(page.path) + dir = ::File.dirname(page.path) + dir = '' if dir == '.' + actor = Grit::Actor.new(commit[:name], commit[:email]) - sha = index.commit(commit[:message], [pcommit], actor) + sha1 = index.commit(commit[:message], [pcommit], actor) + @ref_map.clear - sha + update_working_dir(index, dir, page.name, page.format) + + sha1 end # Public: Lists all pages for this wiki. @@ -277,6 +291,45 @@ module Gollum data.gsub(/\r/, '') end + # Assemble a Page's filename from its name and format. + # + # name - The String name of the page (may be in human format). + # format - The Symbol format of the page. + # + # Returns the String filename. + def page_file_name(name, format) + ext = @page_class.format_to_ext(format) + @page_class.cname(name) + '.' + ext + end + + # Update the given file in the repository's working directory if there + # is a working directory present. + # + # index - The Grit::Index with which to sync. + # dir - The String directory in which the file lives. + # name - The String name of the page (may be in human format). + # format - The Symbol format of the page. + # + # Returns nothing. + def update_working_dir(index, dir, name, format) + unless @repo.bare + path = + if dir == '' + page_file_name(name, format) + else + ::File.join(dir, page_file_name(name, format)) + end + + Dir.chdir(::File.join(@repo.path, '..')) do + if file_path_scheduled_for_deletion?(index.tree, path) + @repo.git.rm({'f' => true}, '--', path) + else + @repo.git.checkout({}, 'HEAD', '--', path) + end + end + end + end + # Fill an array with a list of pages. # # ref - A String ref that is either a commit SHA or references one. @@ -290,8 +343,32 @@ module Gollum end end - # Determine if a given page path is scheduled to be deleted in the next - # commit for the given Index. + # Determine if a given file is scheduled to be deleted in the next commit + # for the given Index. + # + # map - The Hash map: + # key - The String directory or filename. + # val - The Hash submap or the String contents of the file. + # path - The String path of the file including extension. + # + # Returns the Boolean response. + def file_path_scheduled_for_deletion?(map, path) + parts = path.split('/') + if parts.size == 1 + deletions = map.keys.select { |k| !map[k] } + deletions.any? { |d| d == parts.first } + else + part = parts.shift + if rest = map[part] + file_path_scheduled_for_deletion?(rest, parts.join('/')) + else + false + end + end + end + + # Determine if a given page (regardless of format) is scheduled to be + # deleted in the next commit for the given Index. # # map - The Hash map: # key - The String directory or filename. @@ -311,7 +388,7 @@ module Gollum if rest = map[part] page_path_scheduled_for_deletion?(rest, parts.join('/')) else - nil + false end end end @@ -332,8 +409,7 @@ module Gollum # # Returns nothing (modifies the Index in place). def add_to_index(index, dir, name, format, data, allow_same_ext = false) - ext = @page_class.format_to_ext(format) - path = @page_class.cname(name) + '.' + ext + path = page_file_name(name, format) dir = '/' if dir.strip.empty? diff --git a/test/helper.rb b/test/helper.rb index 0b11383e..f6e01ded 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -18,6 +18,12 @@ def testpath(path) File.join(TEST_DIR, path) end +def commit_details + { :message => "Did something at #{Time.now}", + :name => "Tom Preston-Werner", + :email => "tom@github.com" } +end + # test/spec/mini 3 # http://gist.github.com/25455 # chris@ozmm.org @@ -26,7 +32,7 @@ def context(*args, &block) return super unless (name = args.first) && block require 'test/unit' klass = Class.new(defined?(ActiveSupport::TestCase) ? ActiveSupport::TestCase : Test::Unit::TestCase) do - def self.test(name, &block) + def self.test(name, &block) define_method("test_#{name.gsub(/\W/,'_')}", &block) if block end def self.xtest(*args) end diff --git a/test/test_markup.rb b/test/test_markup.rb index 99e37319..0a3e6649 100644 --- a/test/test_markup.rb +++ b/test/test_markup.rb @@ -6,10 +6,6 @@ context "Markup" do FileUtils.rm_rf(@path) Grit::Repo.init_bare(@path) @wiki = Gollum::Wiki.new(@path) - - @commit = { :message => "Add stuff", - :name => "Tom Preston-Werner", - :email => "tom@github.com" } end teardown do @@ -17,12 +13,12 @@ context "Markup" do end test "formats page from Wiki#pages" do - @wiki.write_page("Bilbo Baggins", :markdown, "a [[Foo]][[Bar]] b", @commit) + @wiki.write_page("Bilbo Baggins", :markdown, "a [[Foo]][[Bar]] b", commit_details) assert @wiki.pages[0].formatted_data end test "double page links no space" do - @wiki.write_page("Bilbo Baggins", :markdown, "a [[Foo]][[Bar]] b", @commit) + @wiki.write_page("Bilbo Baggins", :markdown, "a [[Foo]][[Bar]] b", commit_details) # "

a FooBar b

" page = @wiki.page("Bilbo Baggins") @@ -41,7 +37,7 @@ context "Markup" do end test "double page links with space" do - @wiki.write_page("Bilbo Baggins", :markdown, "a [[Foo]] [[Bar]] b", @commit) + @wiki.write_page("Bilbo Baggins", :markdown, "a [[Foo]] [[Bar]] b", commit_details) # "

a Foo Bar b

" page = @wiki.page("Bilbo Baggins") @@ -60,7 +56,7 @@ context "Markup" do end test "page link" do - @wiki.write_page("Bilbo Baggins", :markdown, "a [[Bilbo Baggins]] b", @commit) + @wiki.write_page("Bilbo Baggins", :markdown, "a [[Bilbo Baggins]] b", commit_details) page = @wiki.page("Bilbo Baggins") output = page.formatted_data @@ -70,7 +66,7 @@ context "Markup" do end test "absent page link" do - @wiki.write_page("Tolkien", :markdown, "a [[J. R. R. Tolkien]]'s b", @commit) + @wiki.write_page("Tolkien", :markdown, "a [[J. R. R. Tolkien]]'s b", commit_details) page = @wiki.page("Tolkien") output = page.formatted_data @@ -83,7 +79,7 @@ context "Markup" do ["/wiki", "/wiki/"].each_with_index do |path, i| name = "Bilbo Baggins #{i}" @wiki = Gollum::Wiki.new(@path, :base_path => path) - @wiki.write_page(name, :markdown, "a [[#{name}]] b", @commit) + @wiki.write_page(name, :markdown, "a [[#{name}]] b", commit_details) page = @wiki.page(name) output = page.formatted_data @@ -94,7 +90,7 @@ context "Markup" do end test "external page link" do - @wiki.write_page("Bilbo Baggins", :markdown, "a [[http://example.com]] b", @commit) + @wiki.write_page("Bilbo Baggins", :markdown, "a [[http://example.com]] b", commit_details) page = @wiki.page("Bilbo Baggins") assert_equal "

a http://example.com b

", page.formatted_data @@ -103,7 +99,7 @@ context "Markup" do test "image with http url" do ['http', 'https'].each do |scheme| name = "Bilbo Baggins #{scheme}" - @wiki.write_page(name, :markdown, "a [[#{scheme}://example.com/bilbo.jpg]] b", @commit) + @wiki.write_page(name, :markdown, "a [[#{scheme}://example.com/bilbo.jpg]] b", commit_details) page = @wiki.page(name) output = page.formatted_data @@ -116,7 +112,7 @@ context "Markup" do index = @wiki.repo.index index.add("alpha.jpg", "hi") index.commit("Add alpha.jpg") - @wiki.write_page("Bilbo Baggins", :markdown, "a [[/alpha.jpg]] [[a | /alpha.jpg]] b", @commit) + @wiki.write_page("Bilbo Baggins", :markdown, "a [[/alpha.jpg]] [[a | /alpha.jpg]] b", commit_details) page = @wiki.page("Bilbo Baggins") assert_equal %{

a a b

}, page.formatted_data @@ -221,7 +217,7 @@ context "Markup" do index = @wiki.repo.index index.add("alpha.jpg", "hi") index.commit("Add alpha.jpg") - @wiki.write_page("Bilbo Baggins", :markdown, "a [[Alpha|/alpha.jpg]] b", @commit) + @wiki.write_page("Bilbo Baggins", :markdown, "a [[Alpha|/alpha.jpg]] b", commit_details) page = @wiki.page("Bilbo Baggins") output = Gollum::Markup.new(page).render diff --git a/test/test_wiki.rb b/test/test_wiki.rb index b5f52030..004e48b8 100644 --- a/test/test_wiki.rb +++ b/test/test_wiki.rb @@ -35,7 +35,7 @@ context "Wiki" do test "list pages" do pages = @wiki.pages assert_equal \ - %w(Bilbo-Baggins.md Eye-Of-Sauron.md Home.textile My-Precious.md), + %w(Bilbo-Baggins.md Eye-Of-Sauron.md Home.textile My-Precious.md), pages.map { |p| p.filename }.sort end @@ -107,58 +107,48 @@ context "Wiki page writing" do end test "write_page" do - commit = { :message => "Gollum page", - :name => "Tom Preston-Werner", - :email => "tom@github.com" } - @wiki.write_page("Gollum", :markdown, "# Gollum", commit) + cd = commit_details + @wiki.write_page("Gollum", :markdown, "# Gollum", cd) assert_equal 1, @wiki.repo.commits.size - assert_equal "Gollum page", @wiki.repo.commits.first.message - assert_equal "Tom Preston-Werner", @wiki.repo.commits.first.author.name - assert_equal "tom@github.com", @wiki.repo.commits.first.author.email + assert_equal cd[:message], @wiki.repo.commits.first.message + assert_equal cd[:name], @wiki.repo.commits.first.author.name + assert_equal cd[:email], @wiki.repo.commits.first.author.email assert @wiki.page("Gollum") - @wiki.write_page("Bilbo", :markdown, "# Bilbo", commit) + @wiki.write_page("Bilbo", :markdown, "# Bilbo", commit_details) assert_equal 2, @wiki.repo.commits.size assert @wiki.page("Bilbo") assert @wiki.page("Gollum") end test "is not allowed to overwrite file" do - commit = { :message => "Gollum page", - :name => "Tom Preston-Werner", - :email => "tom@github.com" } - @wiki.write_page("Abc-Def", :markdown, "# Gollum", commit) + @wiki.write_page("Abc-Def", :markdown, "# Gollum", commit_details) assert_raises Gollum::DuplicatePageError do - @wiki.write_page("ABC DEF", :textile, "# Gollum", commit) + @wiki.write_page("ABC DEF", :textile, "# Gollum", commit_details) end end test "update_page" do - commit = { :message => "Gollum page", - :name => "Tom Preston-Werner", - :email => "tom@github.com" } - @wiki.write_page("Gollum", :markdown, "# Gollum", commit) + @wiki.write_page("Gollum", :markdown, "# Gollum", commit_details) page = @wiki.page("Gollum") - @wiki.update_page(page, page.name, :markdown, "# Gollum2", commit) + cd = commit_details + @wiki.update_page(page, page.name, :markdown, "# Gollum2", cd) assert_equal 2, @wiki.repo.commits.size assert_equal "# Gollum2", @wiki.page("Gollum").raw_data - assert_equal "Gollum page", @wiki.repo.commits.first.message - assert_equal "Tom Preston-Werner", @wiki.repo.commits.first.author.name - assert_equal "tom@github.com", @wiki.repo.commits.first.author.email + assert_equal cd[:message], @wiki.repo.commits.first.message + assert_equal cd[:name], @wiki.repo.commits.first.author.name + assert_equal cd[:email], @wiki.repo.commits.first.author.email end test "update page with format change" do - commit = { :message => "Gollum page", - :name => "Tom Preston-Werner", - :email => "tom@github.com" } - @wiki.write_page("Gollum", :markdown, "# Gollum", commit) + @wiki.write_page("Gollum", :markdown, "# Gollum", commit_details) assert_equal :markdown, @wiki.page("Gollum").format page = @wiki.page("Gollum") - @wiki.update_page(page, page.name, :textile, "h1. Gollum", commit) + @wiki.update_page(page, page.name, :textile, "h1. Gollum", commit_details) assert_equal 2, @wiki.repo.commits.size assert_equal :textile, @wiki.page("Gollum").format @@ -166,30 +156,24 @@ context "Wiki page writing" do end test "update page with name change" do - commit = { :message => "Gollum page", - :name => "Tom Preston-Werner", - :email => "tom@github.com" } - @wiki.write_page("Gollum", :markdown, "# Gollum", commit) + @wiki.write_page("Gollum", :markdown, "# Gollum", commit_details) assert_equal :markdown, @wiki.page("Gollum").format page = @wiki.page("Gollum") - @wiki.update_page(page, 'Smeagol', :markdown, "h1. Gollum", commit) + @wiki.update_page(page, 'Smeagol', :markdown, "h1. Gollum", commit_details) assert_equal 2, @wiki.repo.commits.size assert_equal "h1. Gollum", @wiki.page("Smeagol").raw_data end test "update page with name and format change" do - commit = { :message => "Gollum page", - :name => "Tom Preston-Werner", - :email => "tom@github.com" } - @wiki.write_page("Gollum", :markdown, "# Gollum", commit) + @wiki.write_page("Gollum", :markdown, "# Gollum", commit_details) assert_equal :markdown, @wiki.page("Gollum").format page = @wiki.page("Gollum") - @wiki.update_page(page, 'Smeagol', :textile, "h1. Gollum", commit) + @wiki.update_page(page, 'Smeagol', :textile, "h1. Gollum", commit_details) assert_equal 2, @wiki.repo.commits.size assert_equal :textile, @wiki.page("Smeagol").format @@ -197,17 +181,13 @@ context "Wiki page writing" do end test "update nested page with format change" do - commit = { :message => "Gollum page", - :name => "Tom Preston-Werner", - :email => "tom@github.com" } - index = @wiki.repo.index index.add("lotr/Gollum.md", "# Gollum") index.commit("Add nested page") page = @wiki.page("Gollum") assert_equal :markdown, @wiki.page("Gollum").format - @wiki.update_page(page, page.name, :textile, "h1. Gollum", commit) + @wiki.update_page(page, page.name, :textile, "h1. Gollum", commit_details) page = @wiki.page("Gollum") assert_equal "lotr/Gollum.textile", page.path @@ -216,23 +196,16 @@ context "Wiki page writing" do end test "delete root page" do - commit = { :message => "Gollum page", - :name => "Tom Preston-Werner", - :email => "tom@github.com" } - @wiki.write_page("Gollum", :markdown, "# Gollum", commit) + @wiki.write_page("Gollum", :markdown, "# Gollum", commit_details) page = @wiki.page("Gollum") - @wiki.delete_page(page, commit) + @wiki.delete_page(page, commit_details) assert_equal 2, @wiki.repo.commits.size assert_nil @wiki.page("Gollum") end test "delete nested page" do - commit = { :message => "Gollum page", - :name => "Tom Preston-Werner", - :email => "tom@github.com" } - index = @wiki.repo.index index.add("greek/Bilbo-Baggins.md", "hi") index.add("Gollum.md", "hi") @@ -240,7 +213,7 @@ context "Wiki page writing" do page = @wiki.page("Bilbo-Baggins") assert page - @wiki.delete_page(page, commit) + @wiki.delete_page(page, commit_details) assert_equal 2, @wiki.repo.commits.size assert_nil @wiki.page("Bilbo-Baggins") @@ -251,4 +224,59 @@ context "Wiki page writing" do teardown do FileUtils.rm_r(File.join(File.dirname(__FILE__), *%w[examples test.git])) end -end \ No newline at end of file +end + +context "Wiki sync with working directory" do + setup do + @path = testpath('examples/wdtest') + Grit::Repo.init(@path) + @wiki = Gollum::Wiki.new(@path) + end + + test "write a page" do + @wiki.write_page("New Page", :markdown, "Hi", commit_details) + assert_equal "Hi", File.read(File.join(@path, "New-Page.md")) + end + + test "update a page with same name and format" do + @wiki.write_page("New Page", :markdown, "Hi", commit_details) + page = @wiki.page("New Page") + @wiki.update_page(page, page.name, page.format, "Bye", commit_details) + assert_equal "Bye", File.read(File.join(@path, "New-Page.md")) + end + + test "update a page with different name and same format" do + @wiki.write_page("New Page", :markdown, "Hi", commit_details) + page = @wiki.page("New Page") + @wiki.update_page(page, "New Page 2", page.format, "Bye", commit_details) + assert_equal "Bye", File.read(File.join(@path, "New-Page-2.md")) + assert !File.exist?(File.join(@path, "New-Page.md")) + end + + test "update a page with same name and different format" do + @wiki.write_page("New Page", :markdown, "Hi", commit_details) + page = @wiki.page("New Page") + @wiki.update_page(page, page.name, :textile, "Bye", commit_details) + assert_equal "Bye", File.read(File.join(@path, "New-Page.textile")) + assert !File.exist?(File.join(@path, "New-Page.md")) + end + + test "update a page with different name and different format" do + @wiki.write_page("New Page", :markdown, "Hi", commit_details) + page = @wiki.page("New Page") + @wiki.update_page(page, "New Page 2", :textile, "Bye", commit_details) + assert_equal "Bye", File.read(File.join(@path, "New-Page-2.textile")) + assert !File.exist?(File.join(@path, "New-Page.md")) + end + + test "delete a page" do + @wiki.write_page("New Page", :markdown, "Hi", commit_details) + page = @wiki.page("New Page") + @wiki.delete_page(page, commit_details) + assert !File.exist?(File.join(@path, "New-Page.md")) + end + + teardown do + FileUtils.rm_r(@path) + end +end