Class: Gollum::Committer

Inherits:
Object
  • Object
show all
Defined in:
lib/gollum-lib/committer.rb

Overview

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.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(wiki, options = {}) ⇒ Committer

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.



29
30
31
32
33
34
# File 'lib/gollum-lib/committer.rb', line 29

def initialize(wiki, options = {})
  @wiki      = wiki
  @options   = options
  @callbacks = []
  after_commit { |*args| Hook.execute(:post_commit, *args) }
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object

Proxies methods t



239
240
241
# File 'lib/gollum-lib/committer.rb', line 239

def method_missing(name, *args)
  index.send(name, *args)
end

Instance Attribute Details

#optionsObject (readonly)

Gets a Hash of commit options.



12
13
14
# File 'lib/gollum-lib/committer.rb', line 12

def options
  @options
end

#wikiObject (readonly)

Gets the instance of the Gollum::Wiki that is being updated.



9
10
11
# File 'lib/gollum-lib/committer.rb', line 9

def wiki
  @wiki
end

Instance Method Details

#actorObject

Public: The committer for this commit.

Returns a Gollum::Git::Actor.



54
55
56
57
58
59
60
# File 'lib/gollum-lib/committer.rb', line 54

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

#add_to_index(dir, name, format, data, allow_same_ext = false) ⇒ Object

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).



88
89
90
91
92
93
94
95
96
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
126
127
128
129
130
# File 'lib/gollum-lib/committer.rb', line 88

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

#after_commit(&block) ⇒ Object

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.



184
185
186
# File 'lib/gollum-lib/committer.rb', line 184

def after_commit(&block)
  @callbacks << block
end

#commit(update_ref = true) ⇒ Object

Writes the commit to Git and runs the after_commit callbacks.

Returns the String SHA1 of the new commit.



169
170
171
172
173
174
175
176
# File 'lib/gollum-lib/committer.rb', line 169

def commit(update_ref = true)
  head = update_ref ? @wiki.ref : nil
  sha1 = index.commit(@options[:message], parents, actor, nil, head)
  @callbacks.each do |cb|
    cb.call(self, sha1)
  end
  sha1
end

#file_path_scheduled_for_deletion?(map, path) ⇒ Boolean

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.

Returns:

  • (Boolean)


223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/gollum-lib/committer.rb', line 223

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

#indexObject

Public: References the Git index for this commit.

Returns a Gollum::Git::Index.



39
40
41
42
43
44
45
46
47
48
49
# File 'lib/gollum-lib/committer.rb', line 39

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

#page_path_scheduled_for_deletion?(map, path) ⇒ Boolean

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.

Returns:

  • (Boolean)


198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/gollum-lib/committer.rb', line 198

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

#parentsObject

Public: The parent commits to this pending commit.

Returns an array of Gollum::Git::Commit instances.



65
66
67
68
69
70
71
72
# File 'lib/gollum-lib/committer.rb', line 65

def parents
  @parents ||= begin
    arr = [@options[:parent] || @wiki.repo.commit(@wiki.ref)]
    arr.flatten!
    arr.compact!
    arr
  end
end

#update_working_dir(dir, name, format) ⇒ Object

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.



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/gollum-lib/committer.rb', line 141

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