wiki.rb 4.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
module Gitlab
  module Git
    class Wiki
      DuplicatePageError = Class.new(StandardError)

      CommitDetails = Struct.new(:name, :email, :message) do
        def to_h
          { name: name, email: email, message: message }
        end
      end
11
      PageBlob = Struct.new(:name)
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

      def self.default_ref
        'master'
      end

      # Initialize with a Gitlab::Git::Repository instance
      def initialize(repository)
        @repository = repository
      end

      def repository_exists?
        @repository.exists?
      end

      def write_page(name, format, content, commit_details)
27 28 29 30 31 32 33 34
        @repository.gitaly_migrate(:wiki_write_page) do |is_enabled|
          if is_enabled
            gitaly_write_page(name, format, content, commit_details)
            gollum_wiki.clear_cache
          else
            gollum_write_page(name, format, content, commit_details)
          end
        end
35 36 37
      end

      def delete_page(page_path, commit_details)
38 39 40 41 42 43 44 45
        @repository.gitaly_migrate(:wiki_delete_page) do |is_enabled|
          if is_enabled
            gitaly_delete_page(page_path, commit_details)
            gollum_wiki.clear_cache
          else
            gollum_delete_page(page_path, commit_details)
          end
        end
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
      end

      def update_page(page_path, title, format, content, commit_details)
        assert_type!(format, Symbol)
        assert_type!(commit_details, CommitDetails)

        gollum_wiki.update_page(gollum_page_by_path(page_path), title, format, content, commit_details.to_h)
        nil
      end

      def pages
        gollum_wiki.pages.map { |gollum_page| new_page(gollum_page) }
      end

      def page(title:, version: nil, dir: nil)
        if version
          version = Gitlab::Git::Commit.find(@repository, version).id
        end

        gollum_page = gollum_wiki.page(title, version, dir)
        return unless gollum_page

        new_page(gollum_page)
      end

      def file(name, version)
        version ||= self.class.default_ref
        gollum_file = gollum_wiki.file(name, version)
        return unless gollum_file

        Gitlab::Git::WikiFile.new(gollum_file)
      end

      def page_versions(page_path)
        current_page = gollum_page_by_path(page_path)
        current_page.versions.map do |gollum_git_commit|
          gollum_page = gollum_wiki.page(current_page.title, gollum_git_commit.id)
          new_version(gollum_page, gollum_git_commit.id)
        end
      end

      def preview_slug(title, format)
88 89 90 91 92 93 94 95 96
        # Adapted from gollum gem (Gollum::Wiki#preview_page) to avoid
        # using Rugged through a Gollum::Wiki instance
        page_class = Gollum::Page
        page = page_class.new(nil)
        ext = page_class.format_to_ext(format.to_sym)
        name = page_class.cname(title) + '.' + ext
        blob = PageBlob.new(name)
        page.populate(blob)
        page.url_path
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
      end

      private

      def gollum_wiki
        @gollum_wiki ||= Gollum::Wiki.new(@repository.path)
      end

      def gollum_page_by_path(page_path)
        page_name = Gollum::Page.canonicalize_filename(page_path)
        page_dir = File.split(page_path).first

        gollum_wiki.paged(page_name, page_dir)
      end

      def new_page(gollum_page)
        Gitlab::Git::WikiPage.new(gollum_page, new_version(gollum_page, gollum_page.version.id))
      end

      def new_version(gollum_page, commit_id)
        commit = Gitlab::Git::Commit.find(@repository, commit_id)
        Gitlab::Git::WikiPageVersion.new(commit, gollum_page&.format)
      end

      def assert_type!(object, klass)
        unless object.is_a?(klass)
          raise ArgumentError, "expected a #{klass}, got #{object.inspect}"
        end
      end
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141

      def gitaly_wiki_client
        @gitaly_wiki_client ||= Gitlab::GitalyClient::WikiService.new(@repository)
      end

      def gollum_write_page(name, format, content, commit_details)
        assert_type!(format, Symbol)
        assert_type!(commit_details, CommitDetails)

        gollum_wiki.write_page(name, format, content, commit_details.to_h)

        nil
      rescue Gollum::DuplicatePageError => e
        raise Gitlab::Git::Wiki::DuplicatePageError, e.message
      end

142 143 144 145 146 147 148
      def gollum_delete_page(page_path, commit_details)
        assert_type!(commit_details, CommitDetails)

        gollum_wiki.delete_page(gollum_page_by_path(page_path), commit_details.to_h)
        nil
      end

149 150 151
      def gitaly_write_page(name, format, content, commit_details)
        gitaly_wiki_client.write_page(name, format, content, commit_details)
      end
152 153 154 155

      def gitaly_delete_page(page_path, commit_details)
        gitaly_wiki_client.delete_page(page_path, commit_details)
      end
156 157 158
    end
  end
end